@kumix/utils 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":["slugify"],"sources":["../src/constants/country/connect-supported-countries.ts","../src/constants/country/continents.ts","../src/constants/country/countries.ts","../src/constants/country/country-phone-codes.ts","../src/constants/country/regions.ts","../src/constants/domain/cctlds.ts","../src/constants/domain/second.ts","../src/constants/domain/special.ts","../src/constants/colors.ts","../src/constants/env.ts","../src/constants/framer-motion.ts","../src/constants/localhost.ts","../src/constants/reserved-slugs.ts","../src/functions/analytics/google.ts","../src/functions/array/chunk.ts","../src/functions/array/random-value.ts","../src/functions/array/stable-sort.ts","../src/functions/string/assets.ts","../src/functions/browser/construct-metadata.ts","../src/functions/browser/cookies.ts","../src/functions/browser/get-height.ts","../src/functions/browser/resize-image.ts","../src/functions/browser/storage.ts","../src/functions/crypto/base-id.ts","../src/functions/crypto/cuid.ts","../src/functions/crypto/hash-string.ts","../src/functions/crypto/nanoid.ts","../src/functions/datetime/billing-utils.ts","../src/functions/datetime/format-date.ts","../src/functions/datetime/format-datetime-smart.ts","../src/functions/datetime/format-datetime.ts","../src/functions/datetime/format-period.ts","../src/functions/datetime/format-time.ts","../src/functions/datetime/get-datetime-local.ts","../src/functions/datetime/get-days-difference.ts","../src/functions/datetime/get-first-and-last-day.ts","../src/functions/datetime/get-year.ts","../src/functions/datetime/time-ago.ts","../src/functions/datetime/timezone.ts","../src/functions/file/format-file-size.ts","../src/functions/http/fetch-with-retry.ts","../src/functions/http/fetch-with-timeout.ts","../src/functions/http/fetcher.ts","../src/functions/http/ip.ts","../src/functions/http/parse-request.ts","../src/functions/http/recaptcha.ts","../src/functions/logging/slack-log.ts","../src/functions/performance/debounce.ts","../src/functions/performance/throttle.ts","../src/functions/string/auth.ts","../src/functions/string/camel-case.ts","../src/functions/string/capitalize.ts","../src/functions/string/cn.ts","../src/functions/string/combine-words.ts","../src/functions/string/currency-formatter.ts","../src/functions/string/get-initials.ts","../src/functions/string/nformatter.ts","../src/functions/string/normalize-string.ts","../src/functions/string/pluralize.ts","../src/functions/string/regex-escape.ts","../src/functions/string/truncate.ts","../src/functions/string/smart-truncate.ts","../src/functions/string/trim.ts","../src/functions/url/url-validation.ts","../src/functions/url/domains.ts","../src/functions/url/link-constructor.ts","../src/functions/url/search-params.ts","../src/functions/url/url-conversion.ts","../src/functions/url/url-formatting.ts","../src/functions/url/utm-params.ts","../src/functions/validation/deep-equal.ts","../src/functions/validation/email.ts","../src/functions/validation/is-iframeable.ts","../src/functions/validation/keys.ts"],"sourcesContent":["/**\n * Connect Supported Countries\n * Provides a list of country codes supported by the Connect API/service\n */\n\n/**\n * Array of ISO 3166-1 alpha-2 country codes supported by the Connect service\n * Each code is accompanied by a comment with the country name for reference\n *\n * @example\n * ```ts\n * import { CONNECT_SUPPORTED_COUNTRIES } from '@kumix/utils';\n *\n * // Check if a country is supported\n * const isSupported = CONNECT_SUPPORTED_COUNTRIES.includes('US'); // true\n *\n * // Filter users by supported countries\n * const users = [\n * { name: 'John', country: 'US' },\n * { name: 'Alice', country: 'FR' },\n * { name: 'Bob', country: 'ZZ' } // Not supported\n * ];\n * const supportedUsers = users.filter(user =>\n * CONNECT_SUPPORTED_COUNTRIES.includes(user.country)\n * ); // Returns users from US and FR\n *\n * // Display supported countries in a dropdown\n * const countryOptions = CONNECT_SUPPORTED_COUNTRIES.map(code => ({\n * value: code,\n * label: new Intl.DisplayNames(['en'], { type: 'region' }).of(code)\n * }));\n * ```\n */\nexport const CONNECT_SUPPORTED_COUNTRIES = [\n \"AL\", // Albania\n \"DZ\", // Algeria\n \"AO\", // Angola\n \"AG\", // Antigua & Barbuda\n \"AR\", // Argentina\n \"AM\", // Armenia\n \"AU\", // Australia\n \"AT\", // Austria\n \"AZ\", // Azerbaijan\n \"BS\", // Bahamas\n \"BH\", // Bahrain\n \"BD\", // Bangladesh\n \"BE\", // Belgium\n \"BJ\", // Benin\n \"BT\", // Bhutan\n \"BO\", // Bolivia\n \"BA\", // Bosnia & Herzegovina\n \"BW\", // Botswana\n \"BN\", // Brunei\n \"BG\", // Bulgaria\n \"KH\", // Cambodia\n \"CA\", // Canada\n \"CL\", // Chile\n \"CO\", // Colombia\n \"CR\", // Costa Rica\n \"CI\", // Côte d'Ivoire\n \"HR\", // Croatia\n \"CY\", // Cyprus\n \"CZ\", // Czech Republic\n \"DK\", // Denmark\n \"DO\", // Dominican Republic\n \"EC\", // Ecuador\n \"EG\", // Egypt\n \"SV\", // El Salvador\n \"EE\", // Estonia\n \"ET\", // Ethiopia\n \"FI\", // Finland\n \"FR\", // France\n \"GA\", // Gabon\n \"GM\", // Gambia\n \"DE\", // Germany\n \"GH\", // Ghana\n \"GR\", // Greece\n \"GT\", // Guatemala\n \"GY\", // Guyana\n \"HK\", // Hong Kong\n \"HU\", // Hungary\n \"IS\", // Iceland\n \"IN\", // India\n \"ID\", // Indonesia\n \"IE\", // Ireland\n \"IL\", // Israel\n \"IT\", // Italy\n \"JM\", // Jamaica\n \"JP\", // Japan\n \"JO\", // Jordan\n \"KZ\", // Kazakhstan\n \"KE\", // Kenya\n \"KW\", // Kuwait\n \"LA\", // Laos\n \"LV\", // Latvia\n \"LI\", // Liechtenstein\n \"LT\", // Lithuania\n \"LU\", // Luxembourg\n \"MO\", // Macao SAR China\n \"MG\", // Madagascar\n \"MY\", // Malaysia\n \"MT\", // Malta\n \"MU\", // Mauritius\n \"MX\", // Mexico\n \"MD\", // Moldova\n \"MC\", // Monaco\n \"MN\", // Mongolia\n \"MA\", // Morocco\n \"MZ\", // Mozambique\n \"NA\", // Namibia\n \"NL\", // Netherlands\n \"NZ\", // New Zealand\n \"NE\", // Niger\n \"NG\", // Nigeria\n \"MK\", // North Macedonia\n \"NO\", // Norway\n \"OM\", // Oman\n \"PK\", // Pakistan\n \"PA\", // Panama\n \"PY\", // Paraguay\n \"PE\", // Peru\n \"PH\", // Philippines\n \"PL\", // Poland\n \"PT\", // Portugal\n \"QA\", // Qatar\n \"RO\", // Romania\n \"RW\", // Rwanda\n \"SM\", // San Marino\n \"SA\", // Saudi Arabia\n \"SN\", // Senegal\n \"RS\", // Serbia\n \"SG\", // Singapore\n \"SK\", // Slovakia\n \"SI\", // Slovenia\n \"ZA\", // South Africa\n \"KR\", // South Korea\n \"ES\", // Spain\n \"LK\", // Sri Lanka\n \"LC\", // St. Lucia\n \"SE\", // Sweden\n \"CH\", // Switzerland\n \"TW\", // Taiwan\n \"TZ\", // Tanzania\n \"TH\", // Thailand\n \"TT\", // Trinidad & Tobago\n \"TN\", // Tunisia\n \"TR\", // Turkey\n \"AE\", // United Arab Emirates\n \"GB\", // United Kingdom\n \"US\", // United States\n \"UY\", // Uruguay\n \"UZ\", // Uzbekistan\n \"VN\", // Vietnam\n];\n","/**\n * Continent Constants\n * Provides mapping between continent codes and names\n */\n\n/**\n * Object mapping continent codes to their full names\n * Uses standard continent codes as keys\n *\n * @example\n * ```ts\n * import { CONTINENTS } from '@kumix/utils';\n *\n * // Get continent name from code\n * const continentName = CONTINENTS['EU']; // 'Europe'\n *\n * // Check if a code is a valid continent\n * const isValidContinent = 'AS' in CONTINENTS; // true\n *\n * // Display all continents in a dropdown\n * const continentOptions = Object.entries(CONTINENTS).map(([code, name]) => ({\n * value: code,\n * label: name\n * }));\n * ```\n */\nexport const CONTINENTS: { [key: string]: string } = {\n AF: \"Africa\",\n AN: \"Antarctica\",\n AS: \"Asia\",\n EU: \"Europe\",\n NA: \"North America\",\n OC: \"Oceania\",\n SA: \"South America\",\n};\n\n/**\n * Array of all continent codes\n * Useful for iteration, validation, and type checking\n *\n * @example\n * ```ts\n * import { CONTINENT_CODES } from '@kumix/utils';\n *\n * // Validate user input\n * const isValidContinentCode = (code: string) => CONTINENT_CODES.includes(code);\n *\n * // Create a filter for continents\n * const continentFilters = CONTINENT_CODES.map(code => ({\n * id: code,\n * name: CONTINENTS[code],\n * selected: false\n * }));\n * ```\n */\nexport const CONTINENT_CODES = Object.keys(CONTINENTS) as [string, ...string[]];\n","/**\n * Country Constants\n * Provides comprehensive mappings for country codes and names\n */\n\n/**\n * Object mapping ISO 3166-1 alpha-2 country codes to their full names\n * Contains all recognized countries and territories worldwide\n *\n * @example\n * ```ts\n * import { COUNTRIES } from '@kumix/utils';\n *\n * // Get country name from code\n * const countryName = COUNTRIES['US']; // 'United States'\n *\n * // Check if a code is a valid country\n * const isValidCountry = 'FR' in COUNTRIES; // true\n *\n * // Display all countries in a dropdown\n * const countryOptions = Object.entries(COUNTRIES).map(([code, name]) => ({\n * value: code,\n * label: name\n * }));\n * ```\n */\nexport const COUNTRIES: { [key: string]: string } = {\n AF: \"Afghanistan\",\n AL: \"Albania\",\n DZ: \"Algeria\",\n AS: \"American Samoa\",\n AD: \"Andorra\",\n AO: \"Angola\",\n AI: \"Anguilla\",\n AQ: \"Antarctica\",\n AG: \"Antigua and Barbuda\",\n AR: \"Argentina\",\n AM: \"Armenia\",\n AW: \"Aruba\",\n AU: \"Australia\",\n AT: \"Austria\",\n AZ: \"Azerbaijan\",\n BS: \"Bahamas\",\n BH: \"Bahrain\",\n BD: \"Bangladesh\",\n BB: \"Barbados\",\n BY: \"Belarus\",\n BE: \"Belgium\",\n BZ: \"Belize\",\n BJ: \"Benin\",\n BM: \"Bermuda\",\n BT: \"Bhutan\",\n BO: \"Bolivia\",\n BA: \"Bosnia and Herzegovina\",\n BW: \"Botswana\",\n BV: \"Bouvet Island\",\n BR: \"Brazil\",\n IO: \"British Indian Ocean Territory\",\n BN: \"Brunei Darussalam\",\n BG: \"Bulgaria\",\n BF: \"Burkina Faso\",\n BI: \"Burundi\",\n KH: \"Cambodia\",\n CM: \"Cameroon\",\n CA: \"Canada\",\n CV: \"Cape Verde\",\n KY: \"Cayman Islands\",\n CF: \"Central African Republic\",\n TD: \"Chad\",\n CL: \"Chile\",\n CN: \"China\",\n CX: \"Christmas Island\",\n CC: \"Cocos (Keeling) Islands\",\n CO: \"Colombia\",\n KM: \"Comoros\",\n CG: \"Congo (Republic)\",\n CD: \"Congo (Democratic Republic)\",\n CK: \"Cook Islands\",\n CR: \"Costa Rica\",\n CI: \"Ivory Coast\",\n HR: \"Croatia\",\n CU: \"Cuba\",\n CY: \"Cyprus\",\n CZ: \"Czech Republic\",\n DK: \"Denmark\",\n DJ: \"Djibouti\",\n DM: \"Dominica\",\n DO: \"Dominican Republic\",\n EC: \"Ecuador\",\n EG: \"Egypt\",\n SV: \"El Salvador\",\n GQ: \"Equatorial Guinea\",\n ER: \"Eritrea\",\n EE: \"Estonia\",\n ET: \"Ethiopia\",\n FK: \"Falkland Islands\",\n FO: \"Faroe Islands\",\n FJ: \"Fiji\",\n FI: \"Finland\",\n FR: \"France\",\n GF: \"French Guiana\",\n PF: \"French Polynesia\",\n TF: \"French Southern Territories\",\n GA: \"Gabon\",\n GM: \"Gambia\",\n GE: \"Georgia\",\n DE: \"Germany\",\n GH: \"Ghana\",\n GI: \"Gibraltar\",\n GR: \"Greece\",\n GL: \"Greenland\",\n GD: \"Grenada\",\n GP: \"Guadeloupe\",\n GU: \"Guam\",\n GT: \"Guatemala\",\n GN: \"Guinea\",\n GW: \"Guinea-Bissau\",\n GY: \"Guyana\",\n HT: \"Haiti\",\n HM: \"Heard Island and McDonald Islands\",\n VA: \"Vatican City\",\n HN: \"Honduras\",\n HK: \"Hong Kong\",\n HU: \"Hungary\",\n IS: \"Iceland\",\n IN: \"India\",\n ID: \"Indonesia\",\n IR: \"Iran\",\n IQ: \"Iraq\",\n IE: \"Ireland\",\n IL: \"Israel\",\n IT: \"Italy\",\n JM: \"Jamaica\",\n JP: \"Japan\",\n JO: \"Jordan\",\n KZ: \"Kazakhstan\",\n KE: \"Kenya\",\n KI: \"Kiribati\",\n KP: \"North Korea\",\n KR: \"South Korea\",\n KW: \"Kuwait\",\n KG: \"Kyrgyzstan\",\n LA: \"Laos\",\n LV: \"Latvia\",\n LB: \"Lebanon\",\n LS: \"Lesotho\",\n LR: \"Liberia\",\n LY: \"Libya\",\n LI: \"Liechtenstein\",\n LT: \"Lithuania\",\n LU: \"Luxembourg\",\n MO: \"Macao\",\n MG: \"Madagascar\",\n MW: \"Malawi\",\n MY: \"Malaysia\",\n MV: \"Maldives\",\n ML: \"Mali\",\n MT: \"Malta\",\n MH: \"Marshall Islands\",\n MQ: \"Martinique\",\n MR: \"Mauritania\",\n MU: \"Mauritius\",\n YT: \"Mayotte\",\n MX: \"Mexico\",\n FM: \"Micronesia\",\n MD: \"Moldova\",\n MC: \"Monaco\",\n MN: \"Mongolia\",\n MS: \"Montserrat\",\n MA: \"Morocco\",\n MZ: \"Mozambique\",\n MM: \"Myanmar\",\n NA: \"Namibia\",\n NR: \"Nauru\",\n NP: \"Nepal\",\n NL: \"Netherlands\",\n NC: \"New Caledonia\",\n NZ: \"New Zealand\",\n NI: \"Nicaragua\",\n NE: \"Niger\",\n NG: \"Nigeria\",\n NU: \"Niue\",\n NF: \"Norfolk Island\",\n MK: \"Macedonia\",\n MP: \"Northern Mariana Islands\",\n NO: \"Norway\",\n OM: \"Oman\",\n PK: \"Pakistan\",\n PW: \"Palau\",\n PS: \"Palestine\",\n PA: \"Panama\",\n PG: \"Papua New Guinea\",\n PY: \"Paraguay\",\n PE: \"Peru\",\n PH: \"Philippines\",\n PN: \"Pitcairn\",\n PL: \"Poland\",\n PT: \"Portugal\",\n PR: \"Puerto Rico\",\n QA: \"Qatar\",\n RE: \"Reunion\",\n RO: \"Romania\",\n RU: \"Russia\",\n RW: \"Rwanda\",\n SH: \"Saint Helena\",\n KN: \"Saint Kitts and Nevis\",\n LC: \"Saint Lucia\",\n PM: \"Saint Pierre and Miquelon\",\n VC: \"Saint Vincent and the Grenadines\",\n WS: \"Samoa\",\n SM: \"San Marino\",\n ST: \"Sao Tome and Principe\",\n SA: \"Saudi Arabia\",\n SN: \"Senegal\",\n SC: \"Seychelles\",\n SL: \"Sierra Leone\",\n SG: \"Singapore\",\n SK: \"Slovakia\",\n SI: \"Slovenia\",\n SB: \"Solomon Islands\",\n SO: \"Somalia\",\n ZA: \"South Africa\",\n GS: \"South Georgia and the South Sandwich Islands\",\n ES: \"Spain\",\n LK: \"Sri Lanka\",\n SD: \"Sudan\",\n SR: \"Suriname\",\n SJ: \"Svalbard and Jan Mayen\",\n SZ: \"Eswatini\",\n SE: \"Sweden\",\n CH: \"Switzerland\",\n SY: \"Syrian Arab Republic\",\n TW: \"Taiwan\",\n TJ: \"Tajikistan\",\n TZ: \"Tanzania\",\n TH: \"Thailand\",\n TL: \"Timor-Leste\",\n TG: \"Togo\",\n TK: \"Tokelau\",\n TO: \"Tonga\",\n TT: \"Trinidad and Tobago\",\n TN: \"Tunisia\",\n TR: \"Turkey\",\n TM: \"Turkmenistan\",\n TC: \"Turks and Caicos Islands\",\n TV: \"Tuvalu\",\n UG: \"Uganda\",\n UA: \"Ukraine\",\n AE: \"United Arab Emirates\",\n GB: \"United Kingdom\",\n US: \"United States\",\n UM: \"United States Minor Outlying Islands\",\n UY: \"Uruguay\",\n UZ: \"Uzbekistan\",\n VU: \"Vanuatu\",\n VE: \"Venezuela\",\n VN: \"Vietnam\",\n VG: \"Virgin Islands, British\",\n VI: \"Virgin Islands, U.S.\",\n WF: \"Wallis and Futuna\",\n EH: \"Western Sahara\",\n YE: \"Yemen\",\n ZM: \"Zambia\",\n ZW: \"Zimbabwe\",\n AX: \"Åland Islands\",\n BQ: \"Bonaire, Sint Eustatius and Saba\",\n CW: \"Curaçao\",\n GG: \"Guernsey\",\n IM: \"Isle of Man\",\n JE: \"Jersey\",\n ME: \"Montenegro\",\n BL: \"Saint Barthélemy\",\n MF: \"Saint Martin (French part)\",\n RS: \"Serbia\",\n SX: \"Sint Maarten (Dutch part)\",\n SS: \"South Sudan\",\n XK: \"Kosovo\",\n};\n\n/**\n * Array of all ISO 3166-1 alpha-2 country codes\n * Useful for iteration, validation, and type checking\n *\n * @example\n * ```ts\n * import { COUNTRY_CODES } from '@kumix/utils';\n *\n * // Validate user input\n * const isValidCountryCode = (code: string) => COUNTRY_CODES.includes(code);\n *\n * // Create a filter for countries\n * const countryFilters = COUNTRY_CODES.map(code => ({\n * id: code,\n * name: COUNTRIES[code],\n * selected: false\n * }));\n *\n * // Type safety for country code parameters\n * function getCountryData(countryCode: typeof COUNTRY_CODES[number]) {\n * // Function implementation...\n * }\n * ```\n */\nexport const COUNTRY_CODES = Object.keys(COUNTRIES) as [string, ...string[]];\n\n/**\n * Array of ISO 3166-1 alpha-2 country codes for European Union member states\n * Used for EU-specific functionality like GDPR compliance, VAT calculations, etc.\n *\n * @example\n * ```ts\n * import { EU_COUNTRY_CODES, COUNTRIES } from '@kumix/utils';\n *\n * // Check if a country is in the EU\n * const isEUCountry = (countryCode: string) => EU_COUNTRY_CODES.includes(countryCode);\n *\n * // Get list of EU country names\n * const euCountryNames = EU_COUNTRY_CODES.map(code => COUNTRIES[code]);\n *\n * // Filter users from EU countries\n * const euUsers = users.filter(user => EU_COUNTRY_CODES.includes(user.countryCode));\n *\n * // Apply EU-specific logic\n * function applyVAT(price: number, countryCode: string) {\n * if (EU_COUNTRY_CODES.includes(countryCode)) {\n * // Apply EU VAT rules\n * return price * 1.2; // Example VAT rate\n * }\n * return price;\n * }\n * ```\n */\n// EU member states (2020 onwards). The United Kingdom (GB) left the EU in\n// January 2020 (Brexit) and is intentionally excluded. Any EU-specific logic\n// (VAT/GDPR gating) requires this list to be accurate.\nexport const EU_COUNTRY_CODES = [\n \"AT\",\n \"BE\",\n \"BG\",\n \"HR\",\n \"CY\",\n \"CZ\",\n \"DK\",\n \"EE\",\n \"FI\",\n \"FR\",\n \"DE\",\n \"GR\",\n \"HU\",\n \"IE\",\n \"IT\",\n \"LV\",\n \"LT\",\n \"LU\",\n \"MT\",\n \"NL\",\n \"PL\",\n \"PT\",\n \"RO\",\n \"SK\",\n \"SI\",\n \"ES\",\n \"SE\",\n];\n","/**\n * Country Phone Codes\n * Provides mapping between country codes and their international calling codes\n */\n\n/**\n * Object mapping ISO 3166-1 alpha-2 country codes to their international calling codes\n * Used for phone number formatting, validation, and international dialing\n *\n * @example\n * ```ts\n * import { COUNTRY_PHONE_CODES } from '@kumix/utils';\n *\n * // Get phone code from country code\n * const usPhoneCode = COUNTRY_PHONE_CODES['US']; // 1\n *\n * // Format a phone number with international code\n * function formatInternationalPhone(countryCode: string, phoneNumber: string) {\n * const phoneCode = COUNTRY_PHONE_CODES[countryCode];\n * return `+${phoneCode} ${phoneNumber}`;\n * }\n *\n * // Create a phone input with country code selector\n * const phoneOptions = Object.entries(COUNTRY_PHONE_CODES).map(([code, phoneCode]) => ({\n * value: code,\n * label: `${code} (+${phoneCode})`,\n * }));\n *\n * // Note: Some countries share the same phone code (e.g., US and Canada both use +1)\n * ```\n */\nexport const COUNTRY_PHONE_CODES: { [key: string]: number } = {\n AF: 93,\n AL: 355,\n DZ: 213,\n AS: 1,\n AD: 376,\n AO: 244,\n AI: 1,\n AQ: 672,\n AG: 1,\n AR: 54,\n AM: 374,\n AW: 297,\n AU: 61,\n AT: 43,\n AZ: 994,\n BS: 1,\n BH: 973,\n BD: 880,\n BB: 1,\n BY: 375,\n BE: 32,\n BZ: 501,\n BJ: 229,\n BM: 1,\n BT: 975,\n BO: 591,\n BA: 387,\n BW: 267,\n BR: 55,\n IO: 246,\n BN: 673,\n BG: 359,\n BF: 226,\n BI: 257,\n KH: 855,\n CM: 237,\n CA: 1,\n CV: 238,\n KY: 1,\n CF: 236,\n TD: 235,\n CL: 56,\n CN: 86,\n CX: 61,\n CC: 61,\n CO: 57,\n KM: 269,\n CG: 242,\n CD: 243,\n CK: 682,\n CR: 506,\n CI: 225,\n HR: 385,\n CU: 53,\n CY: 357,\n CZ: 420,\n DK: 45,\n DJ: 253,\n DM: 1,\n DO: 1,\n EC: 593,\n EG: 20,\n SV: 503,\n GQ: 240,\n ER: 291,\n EE: 372,\n ET: 251,\n FK: 500,\n FO: 298,\n FJ: 679,\n FI: 358,\n FR: 33,\n GF: 594,\n PF: 689,\n GA: 241,\n GM: 220,\n GE: 995,\n DE: 49,\n GH: 233,\n GI: 350,\n GR: 30,\n GL: 299,\n GD: 1,\n GP: 590,\n GU: 1,\n GT: 502,\n GN: 224,\n GW: 245,\n GY: 592,\n HT: 509,\n VA: 379,\n HN: 504,\n HK: 852,\n HU: 36,\n IS: 354,\n IN: 91,\n ID: 62,\n IR: 98,\n IQ: 964,\n IE: 353,\n IL: 972,\n IT: 39,\n JM: 1,\n JP: 81,\n JO: 962,\n KZ: 7,\n KE: 254,\n KI: 686,\n KP: 850,\n KR: 82,\n KW: 965,\n KG: 996,\n LA: 856,\n LV: 371,\n LB: 961,\n LS: 266,\n LR: 231,\n LY: 218,\n LI: 423,\n LT: 370,\n LU: 352,\n MO: 853,\n MG: 261,\n MW: 265,\n MY: 60,\n MV: 960,\n ML: 223,\n MT: 356,\n MH: 692,\n MQ: 596,\n MR: 222,\n MU: 230,\n YT: 262,\n MX: 52,\n FM: 691,\n MD: 373,\n MC: 377,\n MN: 976,\n MS: 1,\n MA: 212,\n MZ: 258,\n MM: 95,\n NA: 264,\n NR: 674,\n NP: 977,\n NL: 31,\n NC: 687,\n NZ: 64,\n NI: 505,\n NE: 227,\n NG: 234,\n NU: 683,\n NF: 672,\n MK: 389,\n MP: 1,\n NO: 47,\n OM: 968,\n PK: 92,\n PW: 680,\n PS: 970,\n PA: 507,\n PG: 675,\n PY: 595,\n PE: 51,\n PH: 63,\n PN: 64,\n PL: 48,\n PT: 351,\n PR: 1,\n QA: 974,\n RE: 262,\n RO: 40,\n RU: 7,\n RW: 250,\n SH: 290,\n KN: 1,\n LC: 1,\n PM: 508,\n VC: 1,\n WS: 685,\n SM: 378,\n ST: 239,\n SA: 966,\n SN: 221,\n SC: 248,\n SL: 232,\n SG: 65,\n SK: 421,\n SI: 386,\n SB: 677,\n SO: 252,\n ZA: 27,\n ES: 34,\n LK: 94,\n SD: 249,\n SR: 597,\n SZ: 268,\n SE: 46,\n CH: 41,\n SY: 963,\n TW: 886,\n TJ: 992,\n TZ: 255,\n TH: 66,\n TL: 670,\n TG: 228,\n TK: 690,\n TO: 676,\n TT: 1,\n TN: 216,\n TR: 90,\n TM: 993,\n TC: 1,\n TV: 688,\n UG: 256,\n UA: 380,\n AE: 971,\n GB: 44,\n US: 1,\n UY: 598,\n UZ: 998,\n VU: 678,\n VE: 58,\n VN: 84,\n VG: 1,\n VI: 1,\n WF: 681,\n EH: 212,\n YE: 967,\n ZM: 260,\n ZW: 263,\n AX: 358,\n BQ: 599,\n CW: 599,\n GG: 44,\n IM: 44,\n JE: 44,\n ME: 382,\n BL: 590,\n MF: 590,\n RS: 381,\n SX: 1,\n SS: 211,\n XK: 383,\n // BV: null,\n // TF: null,\n // HM: null,\n // GS: null,\n // SJ: null,\n // UM: null,\n};\n","/**\n * Region Constants\n * Provides mapping between region/state/province codes and their names\n */\n\n/**\n * Object mapping region codes to their full names for countries worldwide\n * Uses ISO 3166-2 subdivision codes as keys\n *\n * @example\n * ```ts\n * import { REGIONS } from '@kumix/utils';\n *\n * // Get region name from code\n * const regionName = REGIONS['US-CA']; // 'California'\n *\n * // Check if a code is a valid region\n * const isValidRegion = 'CA-ON' in REGIONS; // true for Ontario, Canada\n *\n * // Get regions for a specific country\n * const usRegions = Object.entries(REGIONS)\n * .filter(([code]) => code.startsWith('US-'))\n * .map(([code, name]) => ({\n * value: code,\n * label: name\n * }));\n *\n * // Display region dropdown based on selected country\n * function getRegionsForCountry(countryCode: string) {\n * return Object.entries(REGIONS)\n * .filter(([code]) => code.startsWith(`${countryCode}-`))\n * .map(([code, name]) => ({\n * value: code,\n * label: name\n * }));\n * }\n * ```\n */\nexport const REGIONS: { [key: string]: string } = {\n \"AF-BDS\": \"Badakhshān\",\n \"AF-BDG\": \"Bādghīs\",\n \"AF-BGL\": \"Baghlān\",\n \"AF-BAL\": \"Balkh\",\n \"AF-BAM\": \"Bāmyān\",\n \"AF-DAY\": \"Dāykundī\",\n \"AF-FRA\": \"Farāh\",\n \"AF-FYB\": \"Fāryāb\",\n \"AF-GHA\": \"Ghaznī\",\n \"AF-GHO\": \"Ghōr\",\n \"AF-HEL\": \"Helmand\",\n \"AF-HER\": \"Herāt\",\n \"AF-JOW\": \"Jowzjān\",\n \"AF-KAB\": \"Kābul\",\n \"AF-KAN\": \"Kandahār\",\n \"AF-KAP\": \"Kāpīsā\",\n \"AF-KHO\": \"Khōst\",\n \"AF-KNR\": \"Kunaṟ\",\n \"AF-KDZ\": \"Kunduz\",\n \"AF-LAG\": \"Laghmān\",\n \"AF-LOG\": \"Lōgar\",\n \"AF-NAN\": \"Nangarhār\",\n \"AF-NIM\": \"Nīmrōz\",\n \"AF-NUR\": \"Nūristān\",\n \"AF-PKA\": \"Paktīkā\",\n \"AF-PIA\": \"Paktiyā\",\n \"AF-PAN\": \"Panjshayr\",\n \"AF-PAR\": \"Parwān\",\n \"AF-SAM\": \"Samangān\",\n \"AF-SAR\": \"Sar-e Pul\",\n \"AF-TAK\": \"Takhār\",\n \"AF-URU\": \"Uruzgān\",\n \"AF-WAR\": \"Wardak\",\n \"AF-ZAB\": \"Zābul\",\n \"AL-01\": \"Berat\",\n \"AL-09\": \"Dibër\",\n \"AL-02\": \"Durrës\",\n \"AL-03\": \"Elbasan\",\n \"AL-04\": \"Fier\",\n \"AL-05\": \"Gjirokastër\",\n \"AL-06\": \"Korçë\",\n \"AL-07\": \"Kukës\",\n \"AL-08\": \"Lezhë\",\n \"AL-10\": \"Shkodër\",\n \"AL-11\": \"Tiranë\",\n \"AL-12\": \"Vlorë\",\n \"DZ-01\": \"Adrar\",\n \"DZ-44\": \"Aïn Defla\",\n \"DZ-46\": \"Aïn Témouchent\",\n \"DZ-16\": \"Alger\",\n \"DZ-23\": \"Annaba\",\n \"DZ-05\": \"Batna\",\n \"DZ-08\": \"Béchar\",\n \"DZ-06\": \"Béjaïa\",\n \"DZ-52\": \"Béni Abbès\",\n \"DZ-07\": \"Biskra\",\n \"DZ-09\": \"Blida\",\n \"DZ-50\": \"Bordj Badji Mokhtar\",\n \"DZ-34\": \"Bordj Bou Arréridj\",\n \"DZ-10\": \"Bouira\",\n \"DZ-35\": \"Boumerdès\",\n \"DZ-02\": \"Chlef\",\n \"DZ-25\": \"Constantine\",\n \"DZ-56\": \"Djanet\",\n \"DZ-17\": \"Djelfa\",\n \"DZ-32\": \"El Bayadh\",\n \"DZ-57\": \"El Meghaier\",\n \"DZ-58\": \"El Meniaa\",\n \"DZ-39\": \"El Oued\",\n \"DZ-36\": \"El Tarf\",\n \"DZ-47\": \"Ghardaïa\",\n \"DZ-24\": \"Guelma\",\n \"DZ-33\": \"Illizi\",\n \"DZ-54\": \"In Guezzam\",\n \"DZ-53\": \"In Salah\",\n \"DZ-18\": \"Jijel\",\n \"DZ-40\": \"Khenchela\",\n \"DZ-03\": \"Laghouat\",\n \"DZ-28\": \"M'sila\",\n \"DZ-29\": \"Mascara\",\n \"DZ-26\": \"Médéa\",\n \"DZ-43\": \"Mila\",\n \"DZ-27\": \"Mostaganem\",\n \"DZ-45\": \"Naama\",\n \"DZ-31\": \"Oran\",\n \"DZ-30\": \"Ouargla\",\n \"DZ-51\": \"Ouled Djellal\",\n \"DZ-04\": \"Oum el Bouaghi\",\n \"DZ-48\": \"Relizane\",\n \"DZ-20\": \"Saïda\",\n \"DZ-19\": \"Sétif\",\n \"DZ-22\": \"Sidi Bel Abbès\",\n \"DZ-21\": \"Skikda\",\n \"DZ-41\": \"Souk Ahras\",\n \"DZ-11\": \"Tamanrasset\",\n \"DZ-12\": \"Tébessa\",\n \"DZ-14\": \"Tiaret\",\n \"DZ-49\": \"Timimoun\",\n \"DZ-37\": \"Tindouf\",\n \"DZ-42\": \"Tipaza\",\n \"DZ-38\": \"Tissemsilt\",\n \"DZ-15\": \"Tizi Ouzou\",\n \"DZ-13\": \"Tlemcen\",\n \"DZ-55\": \"Touggourt\",\n \"AD-07\": \"Andorra la Vella\",\n \"AD-02\": \"Canillo\",\n \"AD-03\": \"Encamp\",\n \"AD-08\": \"Escaldes-Engordany\",\n \"AD-04\": \"La Massana\",\n \"AD-05\": \"Ordino\",\n \"AD-06\": \"Sant Julià de Lòria\",\n \"AO-BGO\": \"Bengo\",\n \"AO-BGU\": \"Benguela\",\n \"AO-BIE\": \"Bié\",\n \"AO-CAB\": \"Cabinda\",\n \"AO-CCU\": \"Cuando Cubango\",\n \"AO-CNO\": \"Cuanza-Norte\",\n \"AO-CUS\": \"Cuanza-Sul\",\n \"AO-CNN\": \"Cunene\",\n \"AO-HUA\": \"Huambo\",\n \"AO-HUI\": \"Huíla\",\n \"AO-LUA\": \"Luanda\",\n \"AO-LNO\": \"Lunda-Norte\",\n \"AO-LSU\": \"Lunda-Sul\",\n \"AO-MAL\": \"Malange\",\n \"AO-MOX\": \"Moxico\",\n \"AO-NAM\": \"Namibe\",\n \"AO-UIG\": \"Uíge\",\n \"AO-ZAI\": \"Zaire\",\n \"AG-03\": \"Saint George\",\n \"AG-04\": \"Saint John\",\n \"AG-05\": \"Saint Mary\",\n \"AG-06\": \"Saint Paul\",\n \"AG-07\": \"Saint Peter\",\n \"AG-08\": \"Saint Philip\",\n \"AG-10\": \"Barbuda\",\n \"AG-11\": \"Redonda\",\n \"AR-B\": \"Buenos Aires\",\n \"AR-K\": \"Catamarca\",\n \"AR-H\": \"Chaco\",\n \"AR-U\": \"Chubut\",\n \"AR-C\": \"Ciudad Autónoma de Buenos Aires\",\n \"AR-X\": \"Córdoba\",\n \"AR-W\": \"Corrientes\",\n \"AR-E\": \"Entre Ríos\",\n \"AR-P\": \"Formosa\",\n \"AR-Y\": \"Jujuy\",\n \"AR-L\": \"La Pampa\",\n \"AR-F\": \"La Rioja\",\n \"AR-M\": \"Mendoza\",\n \"AR-N\": \"Misiones\",\n \"AR-Q\": \"Neuquén\",\n \"AR-R\": \"Río Negro\",\n \"AR-A\": \"Salta\",\n \"AR-J\": \"San Juan\",\n \"AR-D\": \"San Luis\",\n \"AR-Z\": \"Santa Cruz\",\n \"AR-S\": \"Santa Fe\",\n \"AR-G\": \"Santiago del Estero\",\n \"AR-V\": \"Tierra del Fuego\",\n \"AR-T\": \"Tucumán\",\n \"AM-AG\": \"Aragac̣otn\",\n \"AM-AR\": \"Ararat\",\n \"AM-AV\": \"Armavir\",\n \"AM-ER\": \"Erevan\",\n \"AM-GR\": \"Geġark'unik'\",\n \"AM-KT\": \"Kotayk'\",\n \"AM-LO\": \"Loṙi\",\n \"AM-SH\": \"Širak\",\n \"AM-SU\": \"Syunik'\",\n \"AM-TV\": \"Tavuš\",\n \"AM-VD\": \"Vayoć Jor\",\n \"AU-NSW\": \"New South Wales\",\n \"AU-QLD\": \"Queensland\",\n \"AU-SA\": \"South Australia\",\n \"AU-TAS\": \"Tasmania\",\n \"AU-VIC\": \"Victoria\",\n \"AU-WA\": \"Western Australia\",\n \"AU-ACT\": \"Australian Capital Territory\",\n \"AU-NT\": \"Northern Territory\",\n \"AT-1\": \"Burgenland\",\n \"AT-2\": \"Kärnten\",\n \"AT-3\": \"Niederösterreich\",\n \"AT-4\": \"Oberösterreich\",\n \"AT-5\": \"Salzburg\",\n \"AT-6\": \"Steiermark\",\n \"AT-7\": \"Tirol\",\n \"AT-8\": \"Vorarlberg\",\n \"AT-9\": \"Wien\",\n \"AZ-NX\": \"Naxçıvan\",\n \"BS-AK\": \"Acklins\",\n \"BS-BY\": \"Berry Islands\",\n \"BS-BI\": \"Bimini\",\n \"BS-BP\": \"Black Point\",\n \"BS-CI\": \"Cat Island\",\n \"BS-CO\": \"Central Abaco\",\n \"BS-CS\": \"Central Andros\",\n \"BS-CE\": \"Central Eleuthera\",\n \"BS-FP\": \"City of Freeport\",\n \"BS-CK\": \"Crooked Island and Long Cay\",\n \"BS-EG\": \"East Grand Bahama\",\n \"BS-EX\": \"Exuma\",\n \"BS-GC\": \"Grand Cay\",\n \"BS-HI\": \"Harbour Island\",\n \"BS-HT\": \"Hope Town\",\n \"BS-IN\": \"Inagua\",\n \"BS-LI\": \"Long Island\",\n \"BS-MC\": \"Mangrove Cay\",\n \"BS-MG\": \"Mayaguana\",\n \"BS-MI\": \"Moore's Island\",\n \"BS-NP\": \"New Providence\",\n \"BS-NO\": \"North Abaco\",\n \"BS-NS\": \"North Andros\",\n \"BS-NE\": \"North Eleuthera\",\n \"BS-RI\": \"Ragged Island\",\n \"BS-RC\": \"Rum Cay\",\n \"BS-SS\": \"San Salvador\",\n \"BS-SO\": \"South Abaco\",\n \"BS-SA\": \"South Andros\",\n \"BS-SE\": \"South Eleuthera\",\n \"BS-SW\": \"Spanish Wells\",\n \"BS-WG\": \"West Grand Bahama\",\n \"BH-13\": \"Al ‘Āşimah\",\n \"BH-14\": \"Al Janūbīyah\",\n \"BH-15\": \"Al Muḩarraq\",\n \"BH-17\": \"Ash Shamālīyah\",\n \"BD-A\": \"Barishal\",\n \"BD-B\": \"Chattogram\",\n \"BD-C\": \"Dhaka\",\n \"BD-D\": \"Khulna\",\n \"BD-H\": \"Mymensingh\",\n \"BD-E\": \"Rajshahi\",\n \"BD-F\": \"Rangpur\",\n \"BD-G\": \"Sylhet\",\n \"BB-01\": \"Christ Church\",\n \"BB-02\": \"Saint Andrew\",\n \"BB-03\": \"Saint George\",\n \"BB-04\": \"Saint James\",\n \"BB-05\": \"Saint John\",\n \"BB-06\": \"Saint Joseph\",\n \"BB-07\": \"Saint Lucy\",\n \"BB-08\": \"Saint Michael\",\n \"BB-09\": \"Saint Peter\",\n \"BB-10\": \"Saint Philip\",\n \"BB-11\": \"Saint Thomas\",\n \"BY-BR\": \"Brestskaya voblasts'\",\n \"BY-HO\": \"Homyel'skaya voblasts'\",\n \"BY-HM\": \"Horad Minsk\",\n \"BY-HR\": \"Hrodzyenskaya voblasts'\",\n \"BY-MA\": \"Mahilyowskaya voblasts'\",\n \"BY-MI\": \"Minskaya voblasts'\",\n \"BY-VI\": \"Vitsyebskaya voblasts'\",\n \"BE-BRU\": \"Brussels Hoofdstedelijk Gewest\",\n \"BE-VLG\": \"Vlaams Gewest\",\n \"BE-WAL\": \"Waals Gewest\",\n \"BZ-BZ\": \"Belize\",\n \"BZ-CY\": \"Cayo\",\n \"BZ-CZL\": \"Corozal\",\n \"BZ-OW\": \"Orange Walk\",\n \"BZ-SC\": \"Stann Creek\",\n \"BZ-TOL\": \"Toledo\",\n \"BJ-AL\": \"Alibori\",\n \"BJ-AK\": \"Atacora\",\n \"BJ-AQ\": \"Atlantique\",\n \"BJ-BO\": \"Borgou\",\n \"BJ-CO\": \"Collines\",\n \"BJ-KO\": \"Couffo\",\n \"BJ-DO\": \"Donga\",\n \"BJ-LI\": \"Littoral\",\n \"BJ-MO\": \"Mono\",\n \"BJ-OU\": \"Ouémé\",\n \"BJ-PL\": \"Plateau\",\n \"BJ-ZO\": \"Zou\",\n \"BT-33\": \"Bumthang\",\n \"BT-12\": \"Chhukha\",\n \"BT-22\": \"Dagana\",\n \"BT-GA\": \"Gasa\",\n \"BT-13\": \"Haa\",\n \"BT-44\": \"Lhuentse\",\n \"BT-42\": \"Monggar\",\n \"BT-11\": \"Paro\",\n \"BT-43\": \"Pema Gatshel\",\n \"BT-23\": \"Punakha\",\n \"BT-45\": \"Samdrup Jongkhar\",\n \"BT-14\": \"Samtse\",\n \"BT-31\": \"Sarpang\",\n \"BT-15\": \"Thimphu\",\n \"BT-41\": \"Trashigang\",\n \"BT-TY\": \"Trashi Yangtse\",\n \"BT-32\": \"Trongsa\",\n \"BT-21\": \"Tsirang\",\n \"BT-24\": \"Wangdue Phodrang\",\n \"BT-34\": \"Zhemgang\",\n \"BO-C\": \"Cochabamba\",\n \"BO-H\": \"Chuquisaca\",\n \"BO-B\": \"El Beni\",\n \"BO-L\": \"La Paz\",\n \"BO-O\": \"Oruro\",\n \"BO-N\": \"Pando\",\n \"BO-P\": \"Potosí\",\n \"BO-S\": \"Santa Cruz\",\n \"BO-T\": \"Tarija\",\n \"BA-BIH\": \"Federacija Bosne i Hercegovine\",\n \"BA-SRP\": \"Republika Srpska\",\n \"BA-BRC\": \"Brčko distrikt\",\n \"BW-CE\": \"Central\",\n \"BW-CH\": \"Chobe\",\n \"BW-FR\": \"Francistown\",\n \"BW-GA\": \"Gaborone\",\n \"BW-GH\": \"Ghanzi\",\n \"BW-JW\": \"Jwaneng\",\n \"BW-KG\": \"Kgalagadi\",\n \"BW-KL\": \"Kgatleng\",\n \"BW-KW\": \"Kweneng\",\n \"BW-LO\": \"Lobatse\",\n \"BW-NE\": \"North East\",\n \"BW-NW\": \"North West\",\n \"BW-SP\": \"Selibe Phikwe\",\n \"BW-SE\": \"South East\",\n \"BW-SO\": \"Southern\",\n \"BW-ST\": \"Sowa Town\",\n \"BR-AC\": \"Acre\",\n \"BR-AL\": \"Alagoas\",\n \"BR-AP\": \"Amapá\",\n \"BR-AM\": \"Amazonas\",\n \"BR-BA\": \"Bahia\",\n \"BR-CE\": \"Ceará\",\n \"BR-DF\": \"Distrito Federal\",\n \"BR-ES\": \"Espírito Santo\",\n \"BR-GO\": \"Goiás\",\n \"BR-MA\": \"Maranhão\",\n \"BR-MT\": \"Mato Grosso\",\n \"BR-MS\": \"Mato Grosso do Sul\",\n \"BR-MG\": \"Minas Gerais\",\n \"BR-PA\": \"Pará\",\n \"BR-PB\": \"Paraíba\",\n \"BR-PR\": \"Paraná\",\n \"BR-PE\": \"Pernambuco\",\n \"BR-PI\": \"Piauí\",\n \"BR-RJ\": \"Rio de Janeiro\",\n \"BR-RN\": \"Rio Grande do Norte\",\n \"BR-RS\": \"Rio Grande do Sul\",\n \"BR-RO\": \"Rondônia\",\n \"BR-RR\": \"Roraima\",\n \"BR-SC\": \"Santa Catarina\",\n \"BR-SP\": \"São Paulo\",\n \"BR-SE\": \"Sergipe\",\n \"BR-TO\": \"Tocantins\",\n \"BN-BE\": \"Belait\",\n \"BN-BM\": \"Brunei-Muara\",\n \"BN-TE\": \"Temburong\",\n \"BN-TU\": \"Tutong\",\n \"BG-01\": \"Blagoevgrad\",\n \"BG-02\": \"Burgas\",\n \"BG-08\": \"Dobrich\",\n \"BG-07\": \"Gabrovo\",\n \"BG-26\": \"Haskovo\",\n \"BG-09\": \"Kardzhali\",\n \"BG-10\": \"Kyustendil\",\n \"BG-11\": \"Lovech\",\n \"BG-12\": \"Montana\",\n \"BG-13\": \"Pazardzhik\",\n \"BG-14\": \"Pernik\",\n \"BG-15\": \"Pleven\",\n \"BG-16\": \"Plovdiv\",\n \"BG-17\": \"Razgrad\",\n \"BG-18\": \"Ruse\",\n \"BG-27\": \"Shumen\",\n \"BG-19\": \"Silistra\",\n \"BG-20\": \"Sliven\",\n \"BG-21\": \"Smolyan\",\n \"BG-23\": \"Sofia\",\n \"BG-22\": \"Sofia (stolitsa)\",\n \"BG-24\": \"Stara Zagora\",\n \"BG-25\": \"Targovishte\",\n \"BG-03\": \"Varna\",\n \"BG-04\": \"Veliko Tarnovo\",\n \"BG-05\": \"Vidin\",\n \"BG-06\": \"Vratsa\",\n \"BG-28\": \"Yambol\",\n \"BF-01\": \"Boucle du Mouhoun\",\n \"BF-02\": \"Cascades\",\n \"BF-03\": \"Centre\",\n \"BF-04\": \"Centre-Est\",\n \"BF-05\": \"Centre-Nord\",\n \"BF-06\": \"Centre-Ouest\",\n \"BF-07\": \"Centre-Sud\",\n \"BF-08\": \"Est\",\n \"BF-09\": \"Hauts-Bassins\",\n \"BF-10\": \"Nord\",\n \"BF-11\": \"Plateau-Central\",\n \"BF-12\": \"Sahel\",\n \"BF-13\": \"Sud-Ouest\",\n \"BI-BB\": \"Bubanza\",\n \"BI-BM\": \"Bujumbura Mairie\",\n \"BI-BL\": \"Bujumbura Rural\",\n \"BI-BR\": \"Bururi\",\n \"BI-CA\": \"Cankuzo\",\n \"BI-CI\": \"Cibitoke\",\n \"BI-GI\": \"Gitega\",\n \"BI-KR\": \"Karuzi\",\n \"BI-KY\": \"Kayanza\",\n \"BI-KI\": \"Kirundo\",\n \"BI-MA\": \"Makamba\",\n \"BI-MU\": \"Muramvya\",\n \"BI-MY\": \"Muyinga\",\n \"BI-MW\": \"Mwaro\",\n \"BI-NG\": \"Ngozi\",\n \"BI-RM\": \"Rumonge\",\n \"BI-RT\": \"Rutana\",\n \"BI-RY\": \"Ruyigi\",\n \"KH-2\": \"Baat Dambang\",\n \"KH-1\": \"Banteay Mean Choăy\",\n \"KH-23\": \"Kaeb\",\n \"KH-3\": \"Kampong Chaam\",\n \"KH-4\": \"Kampong Chhnang\",\n \"KH-5\": \"Kampong Spueu\",\n \"KH-6\": \"Kampong Thum\",\n \"KH-7\": \"Kampot\",\n \"KH-8\": \"Kandaal\",\n \"KH-9\": \"Kaoh Kong\",\n \"KH-10\": \"Kracheh\",\n \"KH-11\": \"Mondol Kiri\",\n \"KH-22\": \"Otdar Mean Chey\",\n \"KH-24\": \"Pailin\",\n \"KH-12\": \"Phnom Penh\",\n \"KH-15\": \"Pousaat\",\n \"KH-18\": \"Preah Sihanouk\",\n \"KH-13\": \"Preah Vihear\",\n \"KH-14\": \"Prey Veaeng\",\n \"KH-16\": \"Rotanak Kiri\",\n \"KH-17\": \"Siem Reab\",\n \"KH-19\": \"Stueng Traeng\",\n \"KH-20\": \"Svaay Rieng\",\n \"KH-21\": \"Taakaev\",\n \"KH-25\": \"Tbong Khmum\",\n \"CM-AD\": \"Adamaoua\",\n \"CM-CE\": \"Centre\",\n \"CM-ES\": \"East\",\n \"CM-EN\": \"Far North\",\n \"CM-LT\": \"Littoral\",\n \"CM-NO\": \"North\",\n \"CM-NW\": \"North-West\",\n \"CM-SU\": \"South\",\n \"CM-SW\": \"South-West\",\n \"CM-OU\": \"West\",\n \"CA-AB\": \"Alberta\",\n \"CA-BC\": \"British Columbia\",\n \"CA-MB\": \"Manitoba\",\n \"CA-NB\": \"New Brunswick\",\n \"CA-NL\": \"Newfoundland and Labrador\",\n \"CA-NT\": \"Northwest Territories\",\n \"CA-NS\": \"Nova Scotia\",\n \"CA-NU\": \"Nunavut\",\n \"CA-ON\": \"Ontario\",\n \"CA-PE\": \"Prince Edward Island\",\n \"CA-QC\": \"Quebec\",\n \"CA-SK\": \"Saskatchewan\",\n \"CA-YT\": \"Yukon\",\n \"CV-B\": \"Ilhas de Barlavento\",\n \"CV-S\": \"Ilhas de Sotavento\",\n \"CF-BB\": \"Bamingui-Bangoran\",\n \"CF-BGF\": \"Bangui\",\n \"CF-BK\": \"Basse-Kotto\",\n \"CF-KB\": \"Gribingui\",\n \"CF-HM\": \"Haut-Mbomou\",\n \"CF-HK\": \"Haute-Kotto\",\n \"CF-HS\": \"Haute-Sangha / Mambéré-Kadéï\",\n \"CF-KG\": \"Kémo-Gribingui\",\n \"CF-LB\": \"Lobaye\",\n \"CF-MB\": \"Mbomou\",\n \"CF-NM\": \"Nana-Mambéré\",\n \"CF-MP\": \"Ombella-Mpoko\",\n \"CF-UK\": \"Ouaka\",\n \"CF-AC\": \"Ouham\",\n \"CF-OP\": \"Ouham-Pendé\",\n \"CF-SE\": \"Sangha\",\n \"CF-VK\": \"Vakaga\",\n \"TD-BG\": \"Baḩr al Ghazāl\",\n \"TD-BA\": \"Al Baţḩā’\",\n \"TD-BO\": \"Būrkū\",\n \"TD-CB\": \"Shārī Bāqirmī\",\n \"TD-EE\": \"Inīdī ash Sharqī\",\n \"TD-EO\": \"Inīdī al Gharbī\",\n \"TD-GR\": \"Qīrā\",\n \"TD-HL\": \"Ḩajjar Lamīs\",\n \"TD-KA\": \"Kānim\",\n \"TD-LC\": \"Al Buḩayrah\",\n \"TD-LO\": \"Lūghūn al Gharbī\",\n \"TD-LR\": \"Lūghūn ash Sharqī\",\n \"TD-MA\": \"Māndūl\",\n \"TD-ME\": \"Māyū Kībbī ash Sharqī\",\n \"TD-MO\": \"Māyū Kībbī al Gharbī\",\n \"TD-MC\": \"Shārī al Awsaţ\",\n \"TD-OD\": \"Waddāy\",\n \"TD-SA\": \"Salāmāt\",\n \"TD-SI\": \"Sīlā\",\n \"TD-TA\": \"Tānjīlī\",\n \"TD-TI\": \"Tibastī\",\n \"TD-ND\": \"Madīnat Injamīnā\",\n \"TD-WF\": \"Wādī Fīrā’\",\n \"CL-AI\": \"Aisén del General Carlos Ibañez del Campo\",\n \"CL-AN\": \"Antofagasta\",\n \"CL-AP\": \"Arica y Parinacota\",\n \"CL-AT\": \"Atacama\",\n \"CL-BI\": \"Biobío\",\n \"CL-CO\": \"Coquimbo\",\n \"CL-AR\": \"La Araucanía\",\n \"CL-LI\": \"Libertador General Bernardo O'Higgins\",\n \"CL-LL\": \"Los Lagos\",\n \"CL-LR\": \"Los Ríos\",\n \"CL-MA\": \"Magallanes\",\n \"CL-ML\": \"Maule\",\n \"CL-NB\": \"Ñuble\",\n \"CL-RM\": \"Región Metropolitana de Santiago\",\n \"CL-TA\": \"Tarapacá\",\n \"CL-VS\": \"Valparaíso\",\n \"CN-AH\": \"Anhui Sheng\",\n \"CN-BJ\": \"Beijing Shi\",\n \"CN-CQ\": \"Chongqing Shi\",\n \"CN-FJ\": \"Fujian Sheng\",\n \"CN-GS\": \"Gansu Sheng\",\n \"CN-GD\": \"Guangdong Sheng\",\n \"CN-GX\": \"Guangxi Zhuangzu Zizhiqu\",\n \"CN-GZ\": \"Guizhou Sheng\",\n \"CN-HI\": \"Hainan Sheng\",\n \"CN-HE\": \"Hebei Sheng\",\n \"CN-HL\": \"Heilongjiang Sheng\",\n \"CN-HA\": \"Henan Sheng\",\n \"CN-HK\": \"Hong Kong SARen\",\n \"CN-HB\": \"Hubei Sheng\",\n \"CN-HN\": \"Hunan Sheng\",\n \"CN-JS\": \"Jiangsu Sheng\",\n \"CN-JX\": \"Jiangxi Sheng\",\n \"CN-JL\": \"Jilin Sheng\",\n \"CN-LN\": \"Liaoning Sheng\",\n \"CN-MO\": \"Macao SARpt\",\n \"CN-NM\": \"Nei Mongol Zizhiqu\",\n \"CN-NX\": \"Ningxia Huizu Zizhiqu\",\n \"CN-QH\": \"Qinghai Sheng\",\n \"CN-SN\": \"Shaanxi Sheng\",\n \"CN-SD\": \"Shandong Sheng\",\n \"CN-SH\": \"Shanghai Shi\",\n \"CN-SX\": \"Shanxi Sheng\",\n \"CN-SC\": \"Sichuan Sheng\",\n \"CN-TW\": \"Taiwan Sheng\",\n \"CN-TJ\": \"Tianjin Shi\",\n \"CN-XJ\": \"Xinjiang Uygur Zizhiqu\",\n \"CN-XZ\": \"Xizang Zizhiqu\",\n \"CN-YN\": \"Yunnan Sheng\",\n \"CN-ZJ\": \"Zhejiang Sheng\",\n \"CO-AMA\": \"Amazonas\",\n \"CO-ANT\": \"Antioquia\",\n \"CO-ARA\": \"Arauca\",\n \"CO-ATL\": \"Atlántico\",\n \"CO-BOL\": \"Bolívar\",\n \"CO-BOY\": \"Boyacá\",\n \"CO-CAL\": \"Caldas\",\n \"CO-CAQ\": \"Caquetá\",\n \"CO-CAS\": \"Casanare\",\n \"CO-CAU\": \"Cauca\",\n \"CO-CES\": \"Cesar\",\n \"CO-COR\": \"Córdoba\",\n \"CO-CUN\": \"Cundinamarca\",\n \"CO-CHO\": \"Chocó\",\n \"CO-DC\": \"Distrito Capital de Bogotá\",\n \"CO-GUA\": \"Guainía\",\n \"CO-GUV\": \"Guaviare\",\n \"CO-HUI\": \"Huila\",\n \"CO-LAG\": \"La Guajira\",\n \"CO-MAG\": \"Magdalena\",\n \"CO-MET\": \"Meta\",\n \"CO-NAR\": \"Nariño\",\n \"CO-NSA\": \"Norte de Santander\",\n \"CO-PUT\": \"Putumayo\",\n \"CO-QUI\": \"Quindío\",\n \"CO-RIS\": \"Risaralda\",\n \"CO-SAP\": \"San Andrés\",\n \"CO-SAN\": \"Santander\",\n \"CO-SUC\": \"Sucre\",\n \"CO-TOL\": \"Tolima\",\n \"CO-VAC\": \"Valle del Cauca\",\n \"CO-VAU\": \"Vaupés\",\n \"CO-VID\": \"Vichada\",\n \"KM-G\": \"Grande Comore\",\n \"KM-A\": \"Anjouan\",\n \"KM-M\": \"Mohéli\",\n \"CG-11\": \"Bouenza\",\n \"CG-BZV\": \"Brazzaville\",\n \"CG-8\": \"Cuvette\",\n \"CG-15\": \"Cuvette-Ouest\",\n \"CG-5\": \"Kouilou\",\n \"CG-2\": \"Lékoumou\",\n \"CG-7\": \"Likouala\",\n \"CG-9\": \"Niari\",\n \"CG-14\": \"Plateaux\",\n \"CG-16\": \"Pointe-Noire\",\n \"CG-12\": \"Pool\",\n \"CG-13\": \"Sangha\",\n \"CD-BU\": \"Bas-Uélé\",\n \"CD-EQ\": \"Équateur\",\n \"CD-HK\": \"Haut-Katanga\",\n \"CD-HL\": \"Haut-Lomami\",\n \"CD-HU\": \"Haut-Uélé\",\n \"CD-IT\": \"Ituri\",\n \"CD-KS\": \"Kasaï\",\n \"CD-KC\": \"Kasaï Central\",\n \"CD-KE\": \"Kasaï Oriental\",\n \"CD-KN\": \"Kinshasa\",\n \"CD-BC\": \"Kongo Central\",\n \"CD-KG\": \"Kwango\",\n \"CD-KL\": \"Kwilu\",\n \"CD-LO\": \"Lomami\",\n \"CD-LU\": \"Lualaba\",\n \"CD-MN\": \"Mai-Ndombe\",\n \"CD-MA\": \"Maniema\",\n \"CD-MO\": \"Mongala\",\n \"CD-NK\": \"Nord-Kivu\",\n \"CD-NU\": \"Nord-Ubangi\",\n \"CD-SA\": \"Sankuru\",\n \"CD-SK\": \"Sud-Kivu\",\n \"CD-SU\": \"Sud-Ubangi\",\n \"CD-TA\": \"Tanganyika\",\n \"CD-TO\": \"Tshopo\",\n \"CD-TU\": \"Tshuapa\",\n \"CR-A\": \"Alajuela\",\n \"CR-C\": \"Cartago\",\n \"CR-G\": \"Guanacaste\",\n \"CR-H\": \"Heredia\",\n \"CR-L\": \"Limón\",\n \"CR-P\": \"Puntarenas\",\n \"CR-SJ\": \"San José\",\n \"CI-AB\": \"Abidjan\",\n \"CI-BS\": \"Bas-Sassandra\",\n \"CI-CM\": \"Comoé\",\n \"CI-DN\": \"Denguélé\",\n \"CI-GD\": \"Gôh-Djiboua\",\n \"CI-LC\": \"Lacs\",\n \"CI-LG\": \"Lagunes\",\n \"CI-MG\": \"Montagnes\",\n \"CI-SM\": \"Sassandra-Marahoué\",\n \"CI-SV\": \"Savanes\",\n \"CI-VB\": \"Vallée du Bandama\",\n \"CI-WR\": \"Woroba\",\n \"CI-YM\": \"Yamoussoukro\",\n \"CI-ZZ\": \"Zanzan\",\n \"HR-07\": \"Bjelovarsko-bilogorska županija\",\n \"HR-12\": \"Brodsko-posavska županija\",\n \"HR-19\": \"Dubrovačko-neretvanska županija\",\n \"HR-21\": \"Grad Zagreb\",\n \"HR-18\": \"Istarska županija\",\n \"HR-04\": \"Karlovačka županija\",\n \"HR-06\": \"Koprivničko-križevačka županija\",\n \"HR-02\": \"Krapinsko-zagorska županija\",\n \"HR-09\": \"Ličko-senjska županija\",\n \"HR-20\": \"Međimurska županija\",\n \"HR-14\": \"Osječko-baranjska županija\",\n \"HR-11\": \"Požeško-slavonska županija\",\n \"HR-08\": \"Primorsko-goranska županija\",\n \"HR-03\": \"Sisačko-moslavačka županija\",\n \"HR-17\": \"Splitsko-dalmatinska županija\",\n \"HR-15\": \"Šibensko-kninska županija\",\n \"HR-05\": \"Varaždinska županija\",\n \"HR-10\": \"Virovitičko-podravska županija\",\n \"HR-16\": \"Vukovarsko-srijemska županija\",\n \"HR-13\": \"Zadarska županija\",\n \"HR-01\": \"Zagrebačka županija\",\n \"CU-15\": \"Artemisa\",\n \"CU-09\": \"Camagüey\",\n \"CU-08\": \"Ciego de Ávila\",\n \"CU-06\": \"Cienfuegos\",\n \"CU-12\": \"Granma\",\n \"CU-14\": \"Guantánamo\",\n \"CU-11\": \"Holguín\",\n \"CU-03\": \"La Habana\",\n \"CU-10\": \"Las Tunas\",\n \"CU-04\": \"Matanzas\",\n \"CU-16\": \"Mayabeque\",\n \"CU-01\": \"Pinar del Río\",\n \"CU-07\": \"Sancti Spíritus\",\n \"CU-13\": \"Santiago de Cuba\",\n \"CU-05\": \"Villa Clara\",\n \"CU-99\": \"Isla de la Juventud\",\n \"CY-04\": \"Ammochostos\",\n \"CY-06\": \"Keryneia\",\n \"CY-03\": \"Larnaka\",\n \"CY-01\": \"Lefkosia\",\n \"CY-02\": \"Lemesos\",\n \"CY-05\": \"Pafos\",\n \"CZ-31\": \"Jihočeský kraj\",\n \"CZ-64\": \"Jihomoravský kraj\",\n \"CZ-41\": \"Karlovarský kraj\",\n \"CZ-52\": \"Královéhradecký kraj\",\n \"CZ-51\": \"Liberecký kraj\",\n \"CZ-80\": \"Moravskoslezský kraj\",\n \"CZ-71\": \"Olomoucký kraj\",\n \"CZ-53\": \"Pardubický kraj\",\n \"CZ-32\": \"Plzeňský kraj\",\n \"CZ-10\": \"Praha\",\n \"CZ-20\": \"Středočeský kraj\",\n \"CZ-42\": \"Ústecký kraj\",\n \"CZ-63\": \"Kraj Vysočina\",\n \"CZ-72\": \"Zlínský kraj\",\n \"DK-84\": \"Region Hovedstaden\",\n \"DK-82\": \"Region Midjylland\",\n \"DK-81\": \"Region Nordjylland\",\n \"DK-85\": \"Region Sjælland\",\n \"DK-83\": \"Region Syddanmark\",\n \"DJ-AS\": \"Ali Sabieh\",\n \"DJ-AR\": \"Arta\",\n \"DJ-DI\": \"Dikhil\",\n \"DJ-DJ\": \"Djibouti\",\n \"DJ-OB\": \"Obock\",\n \"DJ-TA\": \"Tadjourah\",\n \"DM-02\": \"Saint Andrew\",\n \"DM-03\": \"Saint David\",\n \"DM-04\": \"Saint George\",\n \"DM-05\": \"Saint John\",\n \"DM-06\": \"Saint Joseph\",\n \"DM-07\": \"Saint Luke\",\n \"DM-08\": \"Saint Mark\",\n \"DM-09\": \"Saint Patrick\",\n \"DM-10\": \"Saint Paul\",\n \"DM-11\": \"Saint Peter\",\n \"DO-33\": \"Cibao Nordeste\",\n \"DO-34\": \"Cibao Noroeste\",\n \"DO-35\": \"Cibao Norte\",\n \"DO-36\": \"Cibao Sur\",\n \"DO-37\": \"El Valle\",\n \"DO-38\": \"Enriquillo\",\n \"DO-39\": \"Higuamo\",\n \"DO-40\": \"Ozama\",\n \"DO-41\": \"Valdesia\",\n \"DO-42\": \"Yuma\",\n \"EC-A\": \"Azuay\",\n \"EC-B\": \"Bolívar\",\n \"EC-F\": \"Cañar\",\n \"EC-C\": \"Carchi\",\n \"EC-H\": \"Chimborazo\",\n \"EC-X\": \"Cotopaxi\",\n \"EC-O\": \"El Oro\",\n \"EC-E\": \"Esmeraldas\",\n \"EC-W\": \"Galápagos\",\n \"EC-G\": \"Guayas\",\n \"EC-I\": \"Imbabura\",\n \"EC-L\": \"Loja\",\n \"EC-R\": \"Los Ríos\",\n \"EC-M\": \"Manabí\",\n \"EC-S\": \"Morona Santiago\",\n \"EC-N\": \"Napo\",\n \"EC-D\": \"Orellana\",\n \"EC-Y\": \"Pastaza\",\n \"EC-P\": \"Pichincha\",\n \"EC-SE\": \"Santa Elena\",\n \"EC-SD\": \"Santo Domingo de los Tsáchilas\",\n \"EC-U\": \"Sucumbíos\",\n \"EC-T\": \"Tungurahua\",\n \"EC-Z\": \"Zamora Chinchipe\",\n \"EG-DK\": \"Ad Daqahlīyah\",\n \"EG-BA\": \"Al Baḩr al Aḩmar\",\n \"EG-BH\": \"Al Buḩayrah\",\n \"EG-FYM\": \"Al Fayyūm\",\n \"EG-GH\": \"Al Gharbīyah\",\n \"EG-ALX\": \"Al Iskandarīyah\",\n \"EG-IS\": \"Al Ismā'īlīyah\",\n \"EG-GZ\": \"Al Jīzah\",\n \"EG-MNF\": \"Al Minūfīyah\",\n \"EG-MN\": \"Al Minyā\",\n \"EG-C\": \"Al Qāhirah\",\n \"EG-KB\": \"Al Qalyūbīyah\",\n \"EG-LX\": \"Al Uqşur\",\n \"EG-WAD\": \"Al Wādī al Jadīd\",\n \"EG-SUZ\": \"As Suways\",\n \"EG-SHR\": \"Ash Sharqīyah\",\n \"EG-ASN\": \"Aswān\",\n \"EG-AST\": \"Asyūţ\",\n \"EG-BNS\": \"Banī Suwayf\",\n \"EG-PTS\": \"Būr Sa‘īd\",\n \"EG-DT\": \"Dumyāţ\",\n \"EG-JS\": \"Janūb Sīnā'\",\n \"EG-KFS\": \"Kafr ash Shaykh\",\n \"EG-MT\": \"Maţrūḩ\",\n \"EG-KN\": \"Qinā\",\n \"EG-SIN\": \"Shamāl Sīnā'\",\n \"EG-SHG\": \"Sūhāj\",\n \"SV-AH\": \"Ahuachapán\",\n \"SV-CA\": \"Cabañas\",\n \"SV-CH\": \"Chalatenango\",\n \"SV-CU\": \"Cuscatlán\",\n \"SV-LI\": \"La Libertad\",\n \"SV-PA\": \"La Paz\",\n \"SV-UN\": \"La Unión\",\n \"SV-MO\": \"Morazán\",\n \"SV-SM\": \"San Miguel\",\n \"SV-SS\": \"San Salvador\",\n \"SV-SV\": \"San Vicente\",\n \"SV-SA\": \"Santa Ana\",\n \"SV-SO\": \"Sonsonate\",\n \"SV-US\": \"Usulután\",\n \"GQ-C\": \"Región Continental\",\n \"GQ-I\": \"Región Insular\",\n \"ER-MA\": \"Al Awsaţ\",\n \"ER-DU\": \"Al Janūbī\",\n \"ER-AN\": \"Ansabā\",\n \"ER-DK\": \"Janūbī al Baḩrī al Aḩmar\",\n \"ER-GB\": \"Qāsh-Barkah\",\n \"ER-SK\": \"Shimālī al Baḩrī al Aḩmar\",\n \"EE-37\": \"Harjumaa\",\n \"EE-39\": \"Hiiumaa\",\n \"EE-45\": \"Ida-Virumaa\",\n \"EE-50\": \"Jõgevamaa\",\n \"EE-52\": \"Järvamaa\",\n \"EE-60\": \"Lääne-Virumaa\",\n \"EE-56\": \"Läänemaa\",\n \"EE-64\": \"Põlvamaa\",\n \"EE-68\": \"Pärnumaa\",\n \"EE-71\": \"Raplamaa\",\n \"EE-74\": \"Saaremaa\",\n \"EE-79\": \"Tartumaa\",\n \"EE-81\": \"Valgamaa\",\n \"EE-84\": \"Viljandimaa\",\n \"EE-87\": \"Võrumaa\",\n \"ET-AA\": \"Ādīs Ābeba\",\n \"ET-AF\": \"Āfar\",\n \"ET-AM\": \"Āmara\",\n \"ET-BE\": \"Bīnshangul Gumuz\",\n \"ET-DD\": \"Dirē Dawa\",\n \"ET-GA\": \"Gambēla Hizboch\",\n \"ET-HA\": \"Hārerī Hizb\",\n \"ET-OR\": \"Oromīya\",\n \"ET-SI\": \"Sīdama\",\n \"ET-SO\": \"Sumalē\",\n \"ET-TI\": \"Tigray\",\n \"ET-SN\": \"YeDebub Bihēroch Bihēreseboch na Hizboch\",\n \"ET-SW\": \"YeDebub M‘irab Ītyop’iya Hizboch\",\n \"FJ-C\": \"Central\",\n \"FJ-E\": \"Eastern\",\n \"FJ-N\": \"Northern\",\n \"FJ-W\": \"Western\",\n \"FJ-R\": \"Rotuma\",\n \"FI-01\": \"Ahvenanmaan maakunta\",\n \"FI-02\": \"Etelä-Karjala\",\n \"FI-03\": \"Etelä-Pohjanmaa\",\n \"FI-04\": \"Etelä-Savo\",\n \"FI-05\": \"Kainuu\",\n \"FI-06\": \"Kanta-Häme\",\n \"FI-07\": \"Keski-Pohjanmaa\",\n \"FI-08\": \"Keski-Suomi\",\n \"FI-09\": \"Kymenlaakso\",\n \"FI-10\": \"Lappi\",\n \"FI-11\": \"Pirkanmaa\",\n \"FI-12\": \"Pohjanmaa\",\n \"FI-13\": \"Pohjois-Karjala\",\n \"FI-14\": \"Pohjois-Pohjanmaa\",\n \"FI-15\": \"Pohjois-Savo\",\n \"FI-16\": \"Päijät-Häme\",\n \"FI-17\": \"Satakunta\",\n \"FI-18\": \"Uusimaa\",\n \"FI-19\": \"Varsinais-Suomi\",\n \"FR-ARA\": \"Auvergne-Rhône-Alpes\",\n \"FR-BFC\": \"Bourgogne-Franche-Comté\",\n \"FR-BRE\": \"Bretagne\",\n \"FR-CVL\": \"Centre-Val de Loire\",\n \"FR-20R\": \"Corse\",\n \"FR-GES\": \"Grand Est\",\n \"FR-HDF\": \"Hauts-de-France\",\n \"FR-IDF\": \"Île-de-France\",\n \"FR-NOR\": \"Normandie\",\n \"FR-NAQ\": \"Nouvelle-Aquitaine\",\n \"FR-OCC\": \"Occitanie\",\n \"FR-PDL\": \"Pays-de-la-Loire\",\n \"FR-PAC\": \"Provence-Alpes-Côte-d’Azur\",\n \"GA-1\": \"Estuaire\",\n \"GA-2\": \"Haut-Ogooué\",\n \"GA-3\": \"Moyen-Ogooué\",\n \"GA-4\": \"Ngounié\",\n \"GA-5\": \"Nyanga\",\n \"GA-6\": \"Ogooué-Ivindo\",\n \"GA-7\": \"Ogooué-Lolo\",\n \"GA-8\": \"Ogooué-Maritime\",\n \"GA-9\": \"Woleu-Ntem\",\n \"GM-B\": \"Banjul\",\n \"GM-M\": \"Central River\",\n \"GM-L\": \"Lower River\",\n \"GM-N\": \"North Bank\",\n \"GM-U\": \"Upper River\",\n \"GM-W\": \"Western\",\n \"GE-AB\": \"Abkhazia\",\n \"GE-AJ\": \"Ajaria\",\n \"GE-GU\": \"Guria\",\n \"GE-IM\": \"Imereti\",\n \"GE-KA\": \"K'akheti\",\n \"GE-KK\": \"Kvemo Kartli\",\n \"GE-MM\": \"Mtskheta-Mtianeti\",\n \"GE-RL\": \"Rach'a-Lechkhumi-Kvemo Svaneti\",\n \"GE-SZ\": \"Samegrelo-Zemo Svaneti\",\n \"GE-SJ\": \"Samtskhe-Javakheti\",\n \"GE-SK\": \"Shida Kartli\",\n \"GE-TB\": \"Tbilisi\",\n \"DE-BW\": \"Baden-Württemberg\",\n \"DE-BY\": \"Bayern\",\n \"DE-BE\": \"Berlin\",\n \"DE-BB\": \"Brandenburg\",\n \"DE-HB\": \"Bremen\",\n \"DE-HH\": \"Hamburg\",\n \"DE-HE\": \"Hessen\",\n \"DE-MV\": \"Mecklenburg-Vorpommern\",\n \"DE-NI\": \"Niedersachsen\",\n \"DE-NW\": \"Nordrhein-Westfalen\",\n \"DE-RP\": \"Rheinland-Pfalz\",\n \"DE-SL\": \"Saarland\",\n \"DE-SN\": \"Sachsen\",\n \"DE-ST\": \"Sachsen-Anhalt\",\n \"DE-SH\": \"Schleswig-Holstein\",\n \"DE-TH\": \"Thüringen\",\n \"GH-AF\": \"Ahafo\",\n \"GH-AH\": \"Ashanti\",\n \"GH-BO\": \"Bono\",\n \"GH-BE\": \"Bono East\",\n \"GH-CP\": \"Central\",\n \"GH-EP\": \"Eastern\",\n \"GH-AA\": \"Greater Accra\",\n \"GH-NE\": \"North East\",\n \"GH-NP\": \"Northern\",\n \"GH-OT\": \"Oti\",\n \"GH-SV\": \"Savannah\",\n \"GH-UE\": \"Upper East\",\n \"GH-UW\": \"Upper West\",\n \"GH-TV\": \"Volta\",\n \"GH-WP\": \"Western\",\n \"GH-WN\": \"Western North\",\n \"GR-69\": \"Ágion Óros\",\n \"GR-A\": \"Anatolikí Makedonía kaiThráki\",\n \"GR-I\": \"Attikí\",\n \"GR-G\": \"Dytikí Elláda\",\n \"GR-C\": \"Dytikí Makedonía\",\n \"GR-F\": \"Ionía Nísia\",\n \"GR-D\": \"Ípeiros\",\n \"GR-B\": \"Kentrikí Makedonía\",\n \"GR-M\": \"Kríti\",\n \"GR-L\": \"Nótio Aigaío\",\n \"GR-J\": \"Pelopónnisos\",\n \"GR-H\": \"Stereá Elláda\",\n \"GR-E\": \"Thessalía\",\n \"GR-K\": \"Vóreio Aigaío\",\n \"GL-AV\": \"Avannaata Kommunia\",\n \"GL-KU\": \"Kommune Kujalleq\",\n \"GL-QT\": \"Kommune Qeqertalik\",\n \"GL-SM\": \"Kommuneqarfik Sermersooq\",\n \"GL-QE\": \"Qeqqata Kommunia\",\n \"GD-01\": \"Saint Andrew\",\n \"GD-02\": \"Saint David\",\n \"GD-03\": \"Saint George\",\n \"GD-04\": \"Saint John\",\n \"GD-05\": \"Saint Mark\",\n \"GD-06\": \"Saint Patrick\",\n \"GD-10\": \"Southern Grenadine Islands\",\n \"GT-16\": \"Alta Verapaz\",\n \"GT-15\": \"Baja Verapaz\",\n \"GT-04\": \"Chimaltenango\",\n \"GT-20\": \"Chiquimula\",\n \"GT-02\": \"El Progreso\",\n \"GT-05\": \"Escuintla\",\n \"GT-01\": \"Guatemala\",\n \"GT-13\": \"Huehuetenango\",\n \"GT-18\": \"Izabal\",\n \"GT-21\": \"Jalapa\",\n \"GT-22\": \"Jutiapa\",\n \"GT-17\": \"Petén\",\n \"GT-09\": \"Quetzaltenango\",\n \"GT-14\": \"Quiché\",\n \"GT-11\": \"Retalhuleu\",\n \"GT-03\": \"Sacatepéquez\",\n \"GT-12\": \"San Marcos\",\n \"GT-06\": \"Santa Rosa\",\n \"GT-07\": \"Sololá\",\n \"GT-10\": \"Suchitepéquez\",\n \"GT-08\": \"Totonicapán\",\n \"GT-19\": \"Zacapa\",\n \"GN-B\": \"Boké\",\n \"GN-F\": \"Faranah\",\n \"GN-K\": \"Kankan\",\n \"GN-D\": \"Kindia\",\n \"GN-L\": \"Labé\",\n \"GN-M\": \"Mamou\",\n \"GN-N\": \"Nzérékoré\",\n \"GN-C\": \"Conakry\",\n \"GW-L\": \"Leste\",\n \"GW-N\": \"Norte\",\n \"GW-S\": \"Sul\",\n \"GY-BA\": \"Barima-Waini\",\n \"GY-CU\": \"Cuyuni-Mazaruni\",\n \"GY-DE\": \"Demerara-Mahaica\",\n \"GY-EB\": \"East Berbice-Corentyne\",\n \"GY-ES\": \"Essequibo Islands-West Demerara\",\n \"GY-MA\": \"Mahaica-Berbice\",\n \"GY-PM\": \"Pomeroon-Supenaam\",\n \"GY-PT\": \"Potaro-Siparuni\",\n \"GY-UD\": \"Upper Demerara-Berbice\",\n \"GY-UT\": \"Upper Takutu-Upper Essequibo\",\n \"HT-AR\": \"Artibonite\",\n \"HT-CE\": \"Centre\",\n \"HT-GA\": \"Grande’Anse\",\n \"HT-NI\": \"Nippes\",\n \"HT-ND\": \"Nord\",\n \"HT-NE\": \"Nord-Est\",\n \"HT-NO\": \"Nord-Ouest\",\n \"HT-OU\": \"Ouest\",\n \"HT-SD\": \"Sud\",\n \"HT-SE\": \"Sud-Est\",\n \"HN-AT\": \"Atlántida\",\n \"HN-CH\": \"Choluteca\",\n \"HN-CL\": \"Colón\",\n \"HN-CM\": \"Comayagua\",\n \"HN-CP\": \"Copán\",\n \"HN-CR\": \"Cortés\",\n \"HN-EP\": \"El Paraíso\",\n \"HN-FM\": \"Francisco Morazán\",\n \"HN-GD\": \"Gracias a Dios\",\n \"HN-IN\": \"Intibucá\",\n \"HN-IB\": \"Islas de la Bahía\",\n \"HN-LP\": \"La Paz\",\n \"HN-LE\": \"Lempira\",\n \"HN-OC\": \"Ocotepeque\",\n \"HN-OL\": \"Olancho\",\n \"HN-SB\": \"Santa Bárbara\",\n \"HN-VA\": \"Valle\",\n \"HN-YO\": \"Yoro\",\n \"HU-BK\": \"Bács-Kiskun\",\n \"HU-BA\": \"Baranya\",\n \"HU-BE\": \"Békés\",\n \"HU-BC\": \"Békéscsaba\",\n \"HU-BZ\": \"Borsod-Abaúj-Zemplén\",\n \"HU-BU\": \"Budapest\",\n \"HU-CS\": \"Csongrád-Csanád\",\n \"HU-DE\": \"Debrecen\",\n \"HU-DU\": \"Dunaújváros\",\n \"HU-EG\": \"Eger\",\n \"HU-ER\": \"Érd\",\n \"HU-FE\": \"Fejér\",\n \"HU-GY\": \"Győr\",\n \"HU-GS\": \"Győr-Moson-Sopron\",\n \"HU-HB\": \"Hajdú-Bihar\",\n \"HU-HE\": \"Heves\",\n \"HU-HV\": \"Hódmezővásárhely\",\n \"HU-JN\": \"Jász-Nagykun-Szolnok\",\n \"HU-KV\": \"Kaposvár\",\n \"HU-KM\": \"Kecskemét\",\n \"HU-KE\": \"Komárom-Esztergom\",\n \"HU-MI\": \"Miskolc\",\n \"HU-NK\": \"Nagykanizsa\",\n \"HU-NO\": \"Nógrád\",\n \"HU-NY\": \"Nyíregyháza\",\n \"HU-PS\": \"Pécs\",\n \"HU-PE\": \"Pest\",\n \"HU-ST\": \"Salgótarján\",\n \"HU-SO\": \"Somogy\",\n \"HU-SN\": \"Sopron\",\n \"HU-SZ\": \"Szabolcs-Szatmár-Bereg\",\n \"HU-SD\": \"Szeged\",\n \"HU-SF\": \"Székesfehérvár\",\n \"HU-SS\": \"Szekszárd\",\n \"HU-SK\": \"Szolnok\",\n \"HU-SH\": \"Szombathely\",\n \"HU-TB\": \"Tatabánya\",\n \"HU-TO\": \"Tolna\",\n \"HU-VA\": \"Vas\",\n \"HU-VM\": \"Veszprém\",\n \"HU-VE\": \"Veszprém\",\n \"HU-ZA\": \"Zala\",\n \"HU-ZE\": \"Zalaegerszeg\",\n \"IS-7\": \"Austurland\",\n \"IS-1\": \"Höfuðborgarsvæði\",\n \"IS-6\": \"Norðurland eystra\",\n \"IS-5\": \"Norðurland vestra\",\n \"IS-8\": \"Suðurland\",\n \"IS-2\": \"Suðurnes\",\n \"IS-4\": \"Vestfirðir\",\n \"IS-3\": \"Vesturland\",\n \"IN-AN\": \"Andaman and Nicobar Islands\",\n \"IN-AP\": \"Andhra Pradesh\",\n \"IN-AR\": \"Arunāchal Pradesh\",\n \"IN-AS\": \"Assam\",\n \"IN-BR\": \"Bihār\",\n \"IN-CH\": \"Chandīgarh\",\n \"IN-CG\": \"Chhattīsgarh\",\n \"IN-DH\": \"Dādra and Nagar Haveli and Damān and Diu\",\n \"IN-DL\": \"Delhi\",\n \"IN-GA\": \"Goa\",\n \"IN-GJ\": \"Gujarāt\",\n \"IN-HR\": \"Haryāna\",\n \"IN-HP\": \"Himāchal Pradesh\",\n \"IN-JK\": \"Jammu and Kashmīr\",\n \"IN-JH\": \"Jhārkhand\",\n \"IN-KA\": \"Karnātaka\",\n \"IN-KL\": \"Kerala\",\n \"IN-LA\": \"Ladākh\",\n \"IN-LD\": \"Lakshadweep\",\n \"IN-MP\": \"Madhya Pradesh\",\n \"IN-MH\": \"Mahārāshtra\",\n \"IN-MN\": \"Manipur\",\n \"IN-ML\": \"Meghālaya\",\n \"IN-MZ\": \"Mizoram\",\n \"IN-NL\": \"Nāgāland\",\n \"IN-OD\": \"Odisha\",\n \"IN-PY\": \"Puducherry\",\n \"IN-PB\": \"Punjab\",\n \"IN-RJ\": \"Rājasthān\",\n \"IN-SK\": \"Sikkim\",\n \"IN-TN\": \"Tamil Nādu\",\n \"IN-TS\": \"Telangāna\",\n \"IN-TR\": \"Tripura\",\n \"IN-UP\": \"Uttar Pradesh\",\n \"IN-UK\": \"Uttarākhand\",\n \"IN-WB\": \"West Bengal\",\n \"ID-JW\": \"Jawa\",\n \"ID-KA\": \"Kalimantan\",\n \"ID-ML\": \"Maluku\",\n \"ID-NU\": \"Nusa Tenggara\",\n \"ID-PP\": \"Papua\",\n \"ID-SL\": \"Sulawesi\",\n \"ID-SM\": \"Sumatera\",\n \"IR-30\": \"Alborz\",\n \"IR-24\": \"Ardabīl\",\n \"IR-04\": \"Āz̄ārbāyjān-e Ghārbī\",\n \"IR-03\": \"Āz̄ārbāyjān-e Shārqī\",\n \"IR-18\": \"Būshehr\",\n \"IR-14\": \"Chahār Maḩāl va Bakhtīārī\",\n \"IR-10\": \"Eşfahān\",\n \"IR-07\": \"Fārs\",\n \"IR-01\": \"Gīlān\",\n \"IR-27\": \"Golestān\",\n \"IR-13\": \"Hamadān\",\n \"IR-22\": \"Hormozgān\",\n \"IR-16\": \"Īlām\",\n \"IR-08\": \"Kermān\",\n \"IR-05\": \"Kermānshāh\",\n \"IR-29\": \"Khorāsān-e Jonūbī\",\n \"IR-09\": \"Khorāsān-e Raẕavī\",\n \"IR-28\": \"Khorāsān-e Shomālī\",\n \"IR-06\": \"Khūzestān\",\n \"IR-17\": \"Kohgīlūyeh va Bowyer Aḩmad\",\n \"IR-12\": \"Kordestān\",\n \"IR-15\": \"Lorestān\",\n \"IR-00\": \"Markazī\",\n \"IR-02\": \"Māzandarān\",\n \"IR-26\": \"Qazvīn\",\n \"IR-25\": \"Qom\",\n \"IR-20\": \"Semnān\",\n \"IR-11\": \"Sīstān va Balūchestān\",\n \"IR-23\": \"Tehrān\",\n \"IR-21\": \"Yazd\",\n \"IR-19\": \"Zanjān\",\n \"IQ-AN\": \"Al Anbār\",\n \"IQ-BA\": \"Al Başrah\",\n \"IQ-MU\": \"Al Muthanná\",\n \"IQ-QA\": \"Al Qādisīyah\",\n \"IQ-NA\": \"An Najaf\",\n \"IQ-AR\": \"Arbīl\",\n \"IQ-SU\": \"As Sulaymānīyah\",\n \"IQ-BB\": \"Bābil\",\n \"IQ-BG\": \"Baghdād\",\n \"IQ-DA\": \"Dahūk\",\n \"IQ-DQ\": \"Dhī Qār\",\n \"IQ-DI\": \"Diyālá\",\n \"IQ-KR\": \"Iqlīm Kūrdistān\",\n \"IQ-KA\": \"Karbalā’\",\n \"IQ-KI\": \"Kirkūk\",\n \"IQ-MA\": \"Maysān\",\n \"IQ-NI\": \"Nīnawá\",\n \"IQ-SD\": \"Şalāḩ ad Dīn\",\n \"IQ-WA\": \"Wāsiţ\",\n \"IE-C\": \"Connaught\",\n \"IE-L\": \"Leinster\",\n \"IE-M\": \"Munster\",\n \"IE-U\": \"Ulster\",\n \"IL-D\": \"HaDarom\",\n \"IL-M\": \"HaMerkaz\",\n \"IL-Z\": \"HaTsafon\",\n \"IL-HA\": \"H̱efa\",\n \"IL-TA\": \"Tel Aviv\",\n \"IL-JM\": \"Yerushalayim\",\n \"IT-65\": \"Abruzzo\",\n \"IT-77\": \"Basilicata\",\n \"IT-78\": \"Calabria\",\n \"IT-72\": \"Campania\",\n \"IT-45\": \"Emilia-Romagna\",\n \"IT-36\": \"Friuli Venezia Giulia\",\n \"IT-62\": \"Lazio\",\n \"IT-42\": \"Liguria\",\n \"IT-25\": \"Lombardia\",\n \"IT-57\": \"Marche\",\n \"IT-67\": \"Molise\",\n \"IT-21\": \"Piemonte\",\n \"IT-75\": \"Puglia\",\n \"IT-88\": \"Sardegna\",\n \"IT-82\": \"Sicilia\",\n \"IT-52\": \"Toscana\",\n \"IT-32\": \"Trentino-Alto Adigede\",\n \"IT-55\": \"Umbria\",\n \"IT-23\": \"Valle d'Aostafr\",\n \"IT-34\": \"Veneto\",\n \"JM-13\": \"Clarendon\",\n \"JM-09\": \"Hanover\",\n \"JM-01\": \"Kingston\",\n \"JM-12\": \"Manchester\",\n \"JM-04\": \"Portland\",\n \"JM-02\": \"Saint Andrew\",\n \"JM-06\": \"Saint Ann\",\n \"JM-14\": \"Saint Catherine\",\n \"JM-11\": \"Saint Elizabeth\",\n \"JM-08\": \"Saint James\",\n \"JM-05\": \"Saint Mary\",\n \"JM-03\": \"Saint Thomas\",\n \"JM-07\": \"Trelawny\",\n \"JM-10\": \"Westmoreland\",\n \"JP-23\": \"Aiti\",\n \"JP-05\": \"Akita\",\n \"JP-02\": \"Aomori\",\n \"JP-38\": \"Ehime\",\n \"JP-21\": \"Gihu\",\n \"JP-10\": \"Gunma\",\n \"JP-34\": \"Hirosima\",\n \"JP-01\": \"Hokkaidô\",\n \"JP-18\": \"Hukui\",\n \"JP-40\": \"Hukuoka\",\n \"JP-07\": \"Hukusima\",\n \"JP-28\": \"Hyôgo\",\n \"JP-08\": \"Ibaraki\",\n \"JP-17\": \"Isikawa\",\n \"JP-03\": \"Iwate\",\n \"JP-37\": \"Kagawa\",\n \"JP-46\": \"Kagosima\",\n \"JP-14\": \"Kanagawa\",\n \"JP-39\": \"Kôti\",\n \"JP-43\": \"Kumamoto\",\n \"JP-26\": \"Kyôto\",\n \"JP-24\": \"Mie\",\n \"JP-04\": \"Miyagi\",\n \"JP-45\": \"Miyazaki\",\n \"JP-20\": \"Nagano\",\n \"JP-42\": \"Nagasaki\",\n \"JP-29\": \"Nara\",\n \"JP-15\": \"Niigata\",\n \"JP-44\": \"Ôita\",\n \"JP-33\": \"Okayama\",\n \"JP-47\": \"Okinawa\",\n \"JP-27\": \"Ôsaka\",\n \"JP-41\": \"Saga\",\n \"JP-11\": \"Saitama\",\n \"JP-25\": \"Siga\",\n \"JP-32\": \"Simane\",\n \"JP-22\": \"Sizuoka\",\n \"JP-12\": \"Tiba\",\n \"JP-36\": \"Tokusima\",\n \"JP-13\": \"Tôkyô\",\n \"JP-09\": \"Totigi\",\n \"JP-31\": \"Tottori\",\n \"JP-16\": \"Toyama\",\n \"JP-30\": \"Wakayama\",\n \"JP-06\": \"Yamagata\",\n \"JP-35\": \"Yamaguti\",\n \"JP-19\": \"Yamanasi\",\n \"JO-AJ\": \"‘Ajlūn\",\n \"JO-AQ\": \"Al ‘Aqabah\",\n \"JO-AM\": \"Al ‘A̅şimah\",\n \"JO-BA\": \"Al Balqā’\",\n \"JO-KA\": \"Al Karak\",\n \"JO-MA\": \"Al Mafraq\",\n \"JO-AT\": \"Aţ Ţafīlah\",\n \"JO-AZ\": \"Az Zarqā’\",\n \"JO-IR\": \"Irbid\",\n \"JO-JA\": \"Jarash\",\n \"JO-MN\": \"Ma‘ān\",\n \"JO-MD\": \"Mādabā\",\n \"KZ-10\": \"Abayoblysy\",\n \"KZ-75\": \"Almaty\",\n \"KZ-19\": \"Almatyoblysy\",\n \"KZ-11\": \"Aqmola oblysy\",\n \"KZ-15\": \"Aqtöbe oblysy\",\n \"KZ-71\": \"Astana\",\n \"KZ-23\": \"Atyraūoblysy\",\n \"KZ-27\": \"Batys Qazaqstan oblysy\",\n \"KZ-47\": \"Mangghystaū oblysy\",\n \"KZ-55\": \"Pavlodar oblysy\",\n \"KZ-35\": \"Qaraghandy oblysy\",\n \"KZ-39\": \"Qostanay oblysy\",\n \"KZ-43\": \"Qyzylorda oblysy\",\n \"KZ-63\": \"Shyghys Qazaqstan oblysy\",\n \"KZ-79\": \"Shymkent\",\n \"KZ-59\": \"Soltüstik Qazaqstan oblysy\",\n \"KZ-61\": \"Türkistan oblysy\",\n \"KZ-62\": \"Ulytaūoblysy\",\n \"KZ-31\": \"Zhambyl oblysy\",\n \"KZ-33\": \"Zhetisū oblysy\",\n \"KE-01\": \"Baringo\",\n \"KE-02\": \"Bomet\",\n \"KE-03\": \"Bungoma\",\n \"KE-04\": \"Busia\",\n \"KE-05\": \"Elgeyo/Marakwet\",\n \"KE-06\": \"Embu\",\n \"KE-07\": \"Garissa\",\n \"KE-08\": \"Homa Bay\",\n \"KE-09\": \"Isiolo\",\n \"KE-10\": \"Kajiado\",\n \"KE-11\": \"Kakamega\",\n \"KE-12\": \"Kericho\",\n \"KE-13\": \"Kiambu\",\n \"KE-14\": \"Kilifi\",\n \"KE-15\": \"Kirinyaga\",\n \"KE-16\": \"Kisii\",\n \"KE-17\": \"Kisumu\",\n \"KE-18\": \"Kitui\",\n \"KE-19\": \"Kwale\",\n \"KE-20\": \"Laikipia\",\n \"KE-21\": \"Lamu\",\n \"KE-22\": \"Machakos\",\n \"KE-23\": \"Makueni\",\n \"KE-24\": \"Mandera\",\n \"KE-25\": \"Marsabit\",\n \"KE-26\": \"Meru\",\n \"KE-27\": \"Migori\",\n \"KE-28\": \"Mombasa\",\n \"KE-29\": \"Murang'a\",\n \"KE-30\": \"Nairobi City\",\n \"KE-31\": \"Nakuru\",\n \"KE-32\": \"Nandi\",\n \"KE-33\": \"Narok\",\n \"KE-34\": \"Nyamira\",\n \"KE-35\": \"Nyandarua\",\n \"KE-36\": \"Nyeri\",\n \"KE-37\": \"Samburu\",\n \"KE-38\": \"Siaya\",\n \"KE-39\": \"Taita/Taveta\",\n \"KE-40\": \"Tana River\",\n \"KE-41\": \"Tharaka-Nithi\",\n \"KE-42\": \"Trans Nzoia\",\n \"KE-43\": \"Turkana\",\n \"KE-44\": \"Uasin Gishu\",\n \"KE-45\": \"Vihiga\",\n \"KE-46\": \"Wajir\",\n \"KE-47\": \"West Pokot\",\n \"KI-G\": \"Gilbert Islands\",\n \"KI-L\": \"Line Islands\",\n \"KI-P\": \"Phoenix Islands\",\n \"KP-04\": \"Chagang-do\",\n \"KP-09\": \"Hamgyǒng-bukto\",\n \"KP-08\": \"Hamgyǒng-namdo\",\n \"KP-06\": \"Hwanghae-bukto\",\n \"KP-05\": \"Hwanghae-namdo\",\n \"KP-15\": \"Kaesŏng\",\n \"KP-07\": \"Kangwǒn-do\",\n \"KP-14\": \"Namp’o\",\n \"KP-03\": \"P'yǒngan-bukto\",\n \"KP-02\": \"P'yǒngan-namdo\",\n \"KP-01\": \"P'yǒngyang\",\n \"KP-13\": \"Rasǒn\",\n \"KP-10\": \"Ryanggang-do\",\n \"KR-26\": \"Busan-gwangyeoksi\",\n \"KR-43\": \"Chungcheongbuk-do\",\n \"KR-44\": \"Chungcheongnam-do\",\n \"KR-27\": \"Daegu-gwangyeoksi\",\n \"KR-30\": \"Daejeon-gwangyeoksi\",\n \"KR-42\": \"Gangwon-teukbyeoljachido\",\n \"KR-29\": \"Gwangju-gwangyeoksi\",\n \"KR-41\": \"Gyeonggi-do\",\n \"KR-47\": \"Gyeongsangbuk-do\",\n \"KR-48\": \"Gyeongsangnam-do\",\n \"KR-28\": \"Incheon-gwangyeoksi\",\n \"KR-49\": \"Jeju-teukbyeoljachido\",\n \"KR-45\": \"Jeollabuk-do\",\n \"KR-46\": \"Jeollanam-do\",\n \"KR-50\": \"Sejong\",\n \"KR-11\": \"Seoul-teukbyeolsi\",\n \"KR-31\": \"Ulsan-gwangyeoksi\",\n \"KW-AH\": \"Al Aḩmadī\",\n \"KW-FA\": \"Al Farwānīyah\",\n \"KW-JA\": \"Al Jahrā’\",\n \"KW-KU\": \"Al ‘Āşimah\",\n \"KW-HA\": \"Ḩawallī\",\n \"KW-MU\": \"Mubārak al Kabīr\",\n \"KG-B\": \"Batken\",\n \"KG-GB\": \"Bishkek Shaary\",\n \"KG-C\": \"Chüy\",\n \"KG-J\": \"Jalal-Abad\",\n \"KG-N\": \"Naryn\",\n \"KG-O\": \"Osh\",\n \"KG-GO\": \"Osh Shaary\",\n \"KG-T\": \"Talas\",\n \"KG-Y\": \"Ysyk-Köl\",\n \"LA-AT\": \"Attapu\",\n \"LA-BK\": \"Bokèo\",\n \"LA-BL\": \"Bolikhamxai\",\n \"LA-CH\": \"Champasak\",\n \"LA-HO\": \"Houaphan\",\n \"LA-KH\": \"Khammouan\",\n \"LA-LM\": \"Louang Namtha\",\n \"LA-LP\": \"Louangphabang\",\n \"LA-OU\": \"Oudômxai\",\n \"LA-PH\": \"Phôngsali\",\n \"LA-SL\": \"Salavan\",\n \"LA-SV\": \"Savannakhét\",\n \"LA-VI\": \"Viangchan\",\n \"LA-VT\": \"Viangchan\",\n \"LA-XA\": \"Xaignabouli\",\n \"LA-XS\": \"Xaisômboun\",\n \"LA-XE\": \"Xékong\",\n \"LA-XI\": \"Xiangkhouang\",\n \"LV-002\": \"Aizkraukles novads\",\n \"LV-007\": \"Alūksnes novads\",\n \"LV-111\": \"Augšdaugavas novads\",\n \"LV-011\": \"Ādažu novads\",\n \"LV-015\": \"Balvu novads\",\n \"LV-016\": \"Bauskas novads\",\n \"LV-022\": \"Cēsu novads\",\n \"LV-DGV\": \"Daugavpils\",\n \"LV-112\": \"Dienvidkurzemes Novads\",\n \"LV-026\": \"Dobeles novads\",\n \"LV-033\": \"Gulbenes novads\",\n \"LV-JEL\": \"Jelgava\",\n \"LV-041\": \"Jelgavas novads\",\n \"LV-042\": \"Jēkabpils novads\",\n \"LV-JUR\": \"Jūrmala\",\n \"LV-047\": \"Krāslavas novads\",\n \"LV-050\": \"Kuldīgas novads\",\n \"LV-052\": \"Ķekavas novads\",\n \"LV-LPX\": \"Liepāja\",\n \"LV-054\": \"Limbažu novads\",\n \"LV-056\": \"Līvānu novads\",\n \"LV-058\": \"Ludzas novads\",\n \"LV-059\": \"Madonas novads\",\n \"LV-062\": \"Mārupes novads\",\n \"LV-067\": \"Ogres novads\",\n \"LV-068\": \"Olaines novads\",\n \"LV-073\": \"Preiļu novads\",\n \"LV-REZ\": \"Rēzekne\",\n \"LV-077\": \"Rēzeknes novads\",\n \"LV-RIX\": \"Rīga\",\n \"LV-080\": \"Ropažu novads\",\n \"LV-087\": \"Salaspils novads\",\n \"LV-088\": \"Saldus novads\",\n \"LV-089\": \"Saulkrastu novads\",\n \"LV-091\": \"Siguldas novads\",\n \"LV-094\": \"Smiltenes novads\",\n \"LV-097\": \"Talsu novads\",\n \"LV-099\": \"Tukuma novads\",\n \"LV-101\": \"Valkas novads\",\n \"LV-113\": \"Valmieras Novads\",\n \"LV-102\": \"Varakļānu novads\",\n \"LV-VEN\": \"Ventspils\",\n \"LV-106\": \"Ventspils novads\",\n \"LB-AK\": \"Aakkâr\",\n \"LB-BH\": \"Baalbek-Hermel\",\n \"LB-BI\": \"Béqaa\",\n \"LB-BA\": \"Beyrouth\",\n \"LB-AS\": \"Liban-Nord\",\n \"LB-JA\": \"Liban-Sud\",\n \"LB-JL\": \"Mont-Liban\",\n \"LB-NA\": \"Nabatîyé\",\n \"LS-D\": \"Berea\",\n \"LS-B\": \"Botha-Bothe\",\n \"LS-C\": \"Leribe\",\n \"LS-E\": \"Mafeteng\",\n \"LS-A\": \"Maseru\",\n \"LS-F\": \"Mohale's Hoek\",\n \"LS-J\": \"Mokhotlong\",\n \"LS-H\": \"Qacha's Nek\",\n \"LS-G\": \"Quthing\",\n \"LS-K\": \"Thaba-Tseka\",\n \"LR-BM\": \"Bomi\",\n \"LR-BG\": \"Bong\",\n \"LR-GP\": \"Gbarpolu\",\n \"LR-GB\": \"Grand Bassa\",\n \"LR-CM\": \"Grand Cape Mount\",\n \"LR-GG\": \"Grand Gedeh\",\n \"LR-GK\": \"Grand Kru\",\n \"LR-LO\": \"Lofa\",\n \"LR-MG\": \"Margibi\",\n \"LR-MY\": \"Maryland\",\n \"LR-MO\": \"Montserrado\",\n \"LR-NI\": \"Nimba\",\n \"LR-RI\": \"River Cess\",\n \"LR-RG\": \"River Gee\",\n \"LR-SI\": \"Sinoe\",\n \"LY-BU\": \"Al Buţnān\",\n \"LY-JA\": \"Al Jabal al Akhḑar\",\n \"LY-JG\": \"Al Jabal al Gharbī\",\n \"LY-JI\": \"Al Jafārah\",\n \"LY-JU\": \"Al Jufrah\",\n \"LY-KF\": \"Al Kufrah\",\n \"LY-MJ\": \"Al Marj\",\n \"LY-MB\": \"Al Marqab\",\n \"LY-WA\": \"Al Wāḩāt\",\n \"LY-NQ\": \"An Nuqāţ al Khams\",\n \"LY-ZA\": \"Az Zāwiyah\",\n \"LY-BA\": \"Banghāzī\",\n \"LY-DR\": \"Darnah\",\n \"LY-GT\": \"Ghāt\",\n \"LY-MI\": \"Mişrātah\",\n \"LY-MQ\": \"Murzuq\",\n \"LY-NL\": \"Nālūt\",\n \"LY-SB\": \"Sabhā\",\n \"LY-SR\": \"Surt\",\n \"LY-TB\": \"Ţarābulus\",\n \"LY-WD\": \"Wādī al Ḩayāt\",\n \"LY-WS\": \"Wādī ash Shāţi’\",\n \"LI-01\": \"Balzers\",\n \"LI-02\": \"Eschen\",\n \"LI-03\": \"Gamprin\",\n \"LI-04\": \"Mauren\",\n \"LI-05\": \"Planken\",\n \"LI-06\": \"Ruggell\",\n \"LI-07\": \"Schaan\",\n \"LI-08\": \"Schellenberg\",\n \"LI-09\": \"Triesen\",\n \"LI-10\": \"Triesenberg\",\n \"LI-11\": \"Vaduz\",\n \"LT-AL\": \"Alytaus apskritis\",\n \"LT-KU\": \"Kauno apskritis\",\n \"LT-KL\": \"Klaipėdos apskritis\",\n \"LT-MR\": \"Marijampolės apskritis\",\n \"LT-PN\": \"Panevėžio apskritis\",\n \"LT-SA\": \"Šiaulių apskritis\",\n \"LT-TA\": \"Tauragės apskritis\",\n \"LT-TE\": \"Telšių apskritis\",\n \"LT-UT\": \"Utenos apskritis\",\n \"LT-VL\": \"Vilniaus apskritis\",\n \"LU-CA\": \"Capellen\",\n \"LU-CL\": \"Clervaux\",\n \"LU-DI\": \"Diekirch\",\n \"LU-EC\": \"Echternach\",\n \"LU-ES\": \"Esch-sur-Alzette\",\n \"LU-GR\": \"Grevenmacher\",\n \"LU-LU\": \"Luxembourg\",\n \"LU-ME\": \"Mersch\",\n \"LU-RD\": \"Redange\",\n \"LU-RM\": \"Remich\",\n \"LU-VD\": \"Vianden\",\n \"LU-WI\": \"Wiltz\",\n \"MG-T\": \"Antananarivo\",\n \"MG-D\": \"Antsiranana\",\n \"MG-F\": \"Fianarantsoa\",\n \"MG-M\": \"Mahajanga\",\n \"MG-A\": \"Toamasina\",\n \"MG-U\": \"Toliara\",\n \"MW-N\": \"Chakumpoto\",\n \"MW-S\": \"Chakumwera\",\n \"MW-C\": \"Chapakati\",\n \"MY-01\": \"Johor\",\n \"MY-02\": \"Kedah\",\n \"MY-03\": \"Kelantan\",\n \"MY-04\": \"Melaka\",\n \"MY-05\": \"Negeri Sembilan\",\n \"MY-06\": \"Pahang\",\n \"MY-08\": \"Perak\",\n \"MY-09\": \"Perlis\",\n \"MY-07\": \"Pulau Pinang\",\n \"MY-12\": \"Sabah\",\n \"MY-13\": \"Sarawak\",\n \"MY-10\": \"Selangor\",\n \"MY-11\": \"Terengganu\",\n \"MY-14\": \"Wilayah Persekutuan Kuala Lumpur\",\n \"MY-15\": \"Wilayah Persekutuan Labuan\",\n \"MY-16\": \"Wilayah Persekutuan Putrajaya\",\n \"MV-01\": \"Addu\",\n \"MV-00\": \"Ariatholhu Dhekunuburi\",\n \"MV-02\": \"Ariatholhu Uthuruburi\",\n \"MV-03\": \"Faadhippolhu\",\n \"MV-04\": \"Felidheatholhu\",\n \"MV-29\": \"Fuvammulah\",\n \"MV-05\": \"Hahdhunmathi\",\n \"MV-28\": \"Huvadhuatholhu Dhekunuburi\",\n \"MV-27\": \"Huvadhuatholhu Uthuruburi\",\n \"MV-08\": \"Kolhumadulu\",\n \"MV-MLE\": \"Maale\",\n \"MV-26\": \"Maaleatholhu\",\n \"MV-20\": \"Maalhosmadulu Dhekunuburi\",\n \"MV-13\": \"Maalhosmadulu Uthuruburi\",\n \"MV-25\": \"Miladhunmadulu Dhekunuburi\",\n \"MV-24\": \"Miladhunmadulu Uthuruburi\",\n \"MV-12\": \"Mulakatholhu\",\n \"MV-17\": \"Nilandheatholhu Dhekunuburi\",\n \"MV-14\": \"Nilandheatholhu Uthuruburi\",\n \"MV-23\": \"Thiladhunmathee Dhekunuburi\",\n \"MV-07\": \"Thiladhunmathee Uthuruburi\",\n \"ML-BKO\": \"Bamako\",\n \"ML-7\": \"Gao\",\n \"ML-1\": \"Kayes\",\n \"ML-8\": \"Kidal\",\n \"ML-2\": \"Koulikoro\",\n \"ML-9\": \"Ménaka\",\n \"ML-5\": \"Mopti\",\n \"ML-4\": \"Ségou\",\n \"ML-3\": \"Sikasso\",\n \"ML-10\": \"Taoudénit\",\n \"ML-6\": \"Tombouctou\",\n \"MT-01\": \"Attard\",\n \"MT-02\": \"Balzan\",\n \"MT-03\": \"Birgu\",\n \"MT-04\": \"Birkirkara\",\n \"MT-05\": \"Birżebbuġa\",\n \"MT-06\": \"Bormla\",\n \"MT-07\": \"Dingli\",\n \"MT-08\": \"Fgura\",\n \"MT-09\": \"Floriana\",\n \"MT-10\": \"Fontana\",\n \"MT-11\": \"Gudja\",\n \"MT-12\": \"Gżira\",\n \"MT-13\": \"Għajnsielem\",\n \"MT-14\": \"Għarb\",\n \"MT-15\": \"Għargħur\",\n \"MT-16\": \"Għasri\",\n \"MT-17\": \"Għaxaq\",\n \"MT-18\": \"Ħamrun\",\n \"MT-19\": \"Iklin\",\n \"MT-20\": \"Isla\",\n \"MT-21\": \"Kalkara\",\n \"MT-22\": \"Kerċem\",\n \"MT-23\": \"Kirkop\",\n \"MT-24\": \"Lija\",\n \"MT-25\": \"Luqa\",\n \"MT-26\": \"Marsa\",\n \"MT-27\": \"Marsaskala\",\n \"MT-28\": \"Marsaxlokk\",\n \"MT-29\": \"Mdina\",\n \"MT-30\": \"Mellieħa\",\n \"MT-31\": \"Mġarr\",\n \"MT-32\": \"Mosta\",\n \"MT-33\": \"Mqabba\",\n \"MT-34\": \"Msida\",\n \"MT-35\": \"Mtarfa\",\n \"MT-36\": \"Munxar\",\n \"MT-37\": \"Nadur\",\n \"MT-38\": \"Naxxar\",\n \"MT-39\": \"Paola\",\n \"MT-40\": \"Pembroke\",\n \"MT-41\": \"Pietà\",\n \"MT-42\": \"Qala\",\n \"MT-43\": \"Qormi\",\n \"MT-44\": \"Qrendi\",\n \"MT-45\": \"Rabat Għawdex\",\n \"MT-46\": \"Rabat Malta\",\n \"MT-47\": \"Safi\",\n \"MT-48\": \"San Ġiljan\",\n \"MT-49\": \"San Ġwann\",\n \"MT-50\": \"San Lawrenz\",\n \"MT-51\": \"San Pawl il-Baħar\",\n \"MT-52\": \"Sannat\",\n \"MT-53\": \"Santa Luċija\",\n \"MT-54\": \"Santa Venera\",\n \"MT-55\": \"Siġġiewi\",\n \"MT-56\": \"Sliema\",\n \"MT-57\": \"Swieqi\",\n \"MT-58\": \"Ta' Xbiex\",\n \"MT-59\": \"Tarxien\",\n \"MT-60\": \"Valletta\",\n \"MT-61\": \"Xagħra\",\n \"MT-62\": \"Xewkija\",\n \"MT-63\": \"Xgħajra\",\n \"MT-64\": \"Żabbar\",\n \"MT-65\": \"Żebbuġ Għawdex\",\n \"MT-66\": \"Żebbuġ Malta\",\n \"MT-67\": \"Żejtun\",\n \"MT-68\": \"Żurrieq\",\n \"MH-L\": \"Ralik chain\",\n \"MH-T\": \"Ratak chain\",\n \"MR-07\": \"Adrar\",\n \"MR-03\": \"Assaba\",\n \"MR-05\": \"Brakna\",\n \"MR-08\": \"Dakhlet Nouâdhibou\",\n \"MR-04\": \"Gorgol\",\n \"MR-10\": \"Guidimaka\",\n \"MR-01\": \"Hodh ech Chargui\",\n \"MR-02\": \"Hodh el Gharbi\",\n \"MR-12\": \"Inchiri\",\n \"MR-09\": \"Tagant\",\n \"MR-11\": \"Tiris Zemmour\",\n \"MR-06\": \"Trarza\",\n \"MU-AG\": \"Agalega Islands\",\n \"MU-BL\": \"Black River\",\n \"MU-CC\": \"Cargados Carajos Shoals\",\n \"MU-FL\": \"Flacq\",\n \"MU-GP\": \"Grand Port\",\n \"MU-MO\": \"Moka\",\n \"MU-PA\": \"Pamplemousses\",\n \"MU-PW\": \"Plaines Wilhems\",\n \"MU-PL\": \"Port Louis\",\n \"MU-RR\": \"Rivière du Rempart\",\n \"MU-RO\": \"Rodrigues Island\",\n \"MU-SA\": \"Savanne\",\n \"MX-AGU\": \"Aguascalientes\",\n \"MX-BCN\": \"Baja California\",\n \"MX-BCS\": \"Baja California Sur\",\n \"MX-CAM\": \"Campeche\",\n \"MX-CMX\": \"Ciudad de México\",\n \"MX-COA\": \"Coahuila de Zaragoza\",\n \"MX-COL\": \"Colima\",\n \"MX-CHP\": \"Chiapas\",\n \"MX-CHH\": \"Chihuahua\",\n \"MX-DUR\": \"Durango\",\n \"MX-GUA\": \"Guanajuato\",\n \"MX-GRO\": \"Guerrero\",\n \"MX-HID\": \"Hidalgo\",\n \"MX-JAL\": \"Jalisco\",\n \"MX-MEX\": \"México\",\n \"MX-MIC\": \"Michoacán de Ocampo\",\n \"MX-MOR\": \"Morelos\",\n \"MX-NAY\": \"Nayarit\",\n \"MX-NLE\": \"Nuevo León\",\n \"MX-OAX\": \"Oaxaca\",\n \"MX-PUE\": \"Puebla\",\n \"MX-QUE\": \"Querétaro\",\n \"MX-ROO\": \"Quintana Roo\",\n \"MX-SLP\": \"San Luis Potosí\",\n \"MX-SIN\": \"Sinaloa\",\n \"MX-SON\": \"Sonora\",\n \"MX-TAB\": \"Tabasco\",\n \"MX-TAM\": \"Tamaulipas\",\n \"MX-TLA\": \"Tlaxcala\",\n \"MX-VER\": \"Veracruz de Ignacio de la Llave\",\n \"MX-YUC\": \"Yucatán\",\n \"MX-ZAC\": \"Zacatecas\",\n \"FM-TRK\": \"Chuuk\",\n \"FM-KSA\": \"Kosrae\",\n \"FM-PNI\": \"Pohnpei\",\n \"FM-YAP\": \"Yap\",\n \"MD-AN\": \"Anenii Noi\",\n \"MD-BS\": \"Basarabeasca\",\n \"MD-BA\": \"Bălți\",\n \"MD-BD\": \"Bender\",\n \"MD-BR\": \"Briceni\",\n \"MD-CA\": \"Cahul\",\n \"MD-CT\": \"Cantemir\",\n \"MD-CL\": \"Călărași\",\n \"MD-CS\": \"Căușeni\",\n \"MD-CU\": \"Chișinău\",\n \"MD-CM\": \"Cimișlia\",\n \"MD-CR\": \"Criuleni\",\n \"MD-DO\": \"Dondușeni\",\n \"MD-DR\": \"Drochia\",\n \"MD-DU\": \"Dubăsari\",\n \"MD-ED\": \"Edineț\",\n \"MD-FA\": \"Fălești\",\n \"MD-FL\": \"Florești\",\n \"MD-GA\": \"Găgăuzia\",\n \"MD-GL\": \"Glodeni\",\n \"MD-HI\": \"Hîncești\",\n \"MD-IA\": \"Ialoveni\",\n \"MD-LE\": \"Leova\",\n \"MD-NI\": \"Nisporeni\",\n \"MD-OC\": \"Ocnița\",\n \"MD-OR\": \"Orhei\",\n \"MD-RE\": \"Rezina\",\n \"MD-RI\": \"Rîșcani\",\n \"MD-SI\": \"Sîngerei\",\n \"MD-SO\": \"Soroca\",\n \"MD-SN\": \"Stînga Nistrului\",\n \"MD-ST\": \"Strășeni\",\n \"MD-SD\": \"Șoldănești\",\n \"MD-SV\": \"Ștefan Vodă\",\n \"MD-TA\": \"Taraclia\",\n \"MD-TE\": \"Telenești\",\n \"MD-UN\": \"Ungheni\",\n \"MC-FO\": \"Fontvieille\",\n \"MC-JE\": \"Jardin Exotique\",\n \"MC-CL\": \"La Colle\",\n \"MC-CO\": \"La Condamine\",\n \"MC-GA\": \"La Gare\",\n \"MC-SO\": \"La Source\",\n \"MC-LA\": \"Larvotto\",\n \"MC-MA\": \"Malbousquet\",\n \"MC-MO\": \"Monaco-Ville\",\n \"MC-MG\": \"Moneghetti\",\n \"MC-MC\": \"Monte-Carlo\",\n \"MC-MU\": \"Moulins\",\n \"MC-PH\": \"Port-Hercule\",\n \"MC-SR\": \"Saint-Roman\",\n \"MC-SD\": \"Sainte-Dévote\",\n \"MC-SP\": \"Spélugues\",\n \"MC-VR\": \"Vallon de la Rousse\",\n \"MN-073\": \"Arhangay\",\n \"MN-069\": \"Bayanhongor\",\n \"MN-071\": \"Bayan-Ölgiy\",\n \"MN-067\": \"Bulgan\",\n \"MN-037\": \"Darhan uul\",\n \"MN-061\": \"Dornod\",\n \"MN-063\": \"Dornogovĭ\",\n \"MN-059\": \"Dundgovĭ\",\n \"MN-057\": \"Dzavhan\",\n \"MN-065\": \"Govĭ-Altay\",\n \"MN-064\": \"Govĭ-Sümber\",\n \"MN-039\": \"Hentiy\",\n \"MN-043\": \"Hovd\",\n \"MN-041\": \"Hövsgöl\",\n \"MN-053\": \"Ömnögovĭ\",\n \"MN-035\": \"Orhon\",\n \"MN-055\": \"Övörhangay\",\n \"MN-049\": \"Selenge\",\n \"MN-051\": \"Sühbaatar\",\n \"MN-047\": \"Töv\",\n \"MN-1\": \"Ulaanbaatar\",\n \"MN-046\": \"Uvs\",\n \"MA-05\": \"Béni Mellal-Khénifra\",\n \"MA-06\": \"Casablanca-Settat\",\n \"MA-12\": \"Dakhla-Oued Ed-Dahab\",\n \"MA-08\": \"Drâa-Tafilalet\",\n \"MA-03\": \"Fès-Meknès\",\n \"MA-10\": \"Guelmim-Oued Noun\",\n \"MA-02\": \"L'Oriental\",\n \"MA-11\": \"Laâyoune-Sakia El Hamra\",\n \"MA-07\": \"Marrakech-Safi\",\n \"MA-04\": \"Rabat-Salé-Kénitra\",\n \"MA-09\": \"Souss-Massa\",\n \"MA-01\": \"Tanger-Tétouan-Al Hoceïma\",\n \"MZ-P\": \"Cabo Delgado\",\n \"MZ-G\": \"Gaza\",\n \"MZ-I\": \"Inhambane\",\n \"MZ-B\": \"Manica\",\n \"MZ-MPM\": \"Maputo\",\n \"MZ-L\": \"Maputo\",\n \"MZ-N\": \"Nampula\",\n \"MZ-A\": \"Niassa\",\n \"MZ-S\": \"Sofala\",\n \"MZ-T\": \"Tete\",\n \"MZ-Q\": \"Zambézia\",\n \"MM-07\": \"Ayeyarwady\",\n \"MM-02\": \"Bago\",\n \"MM-14\": \"Chin\",\n \"MM-11\": \"Kachin\",\n \"MM-12\": \"Kayah\",\n \"MM-13\": \"Kayin\",\n \"MM-03\": \"Magway\",\n \"MM-04\": \"Mandalay\",\n \"MM-15\": \"Mon\",\n \"MM-18\": \"Nay Pyi Taw\",\n \"MM-16\": \"Rakhine\",\n \"MM-01\": \"Sagaing\",\n \"MM-17\": \"Shan\",\n \"MM-05\": \"Tanintharyi\",\n \"MM-06\": \"Yangon\",\n \"NA-ER\": \"Erongo\",\n \"NA-HA\": \"Hardap\",\n \"NA-KA\": \"//Karas\",\n \"NA-KE\": \"Kavango East\",\n \"NA-KW\": \"Kavango West\",\n \"NA-KH\": \"Khomas\",\n \"NA-KU\": \"Kunene\",\n \"NA-OW\": \"Ohangwena\",\n \"NA-OH\": \"Omaheke\",\n \"NA-OS\": \"Omusati\",\n \"NA-ON\": \"Oshana\",\n \"NA-OT\": \"Oshikoto\",\n \"NA-OD\": \"Otjozondjupa\",\n \"NA-CA\": \"Zambezi\",\n \"NR-01\": \"Aiwo\",\n \"NR-02\": \"Anabar\",\n \"NR-03\": \"Anetan\",\n \"NR-04\": \"Anibare\",\n \"NR-05\": \"Baitsi\",\n \"NR-06\": \"Boe\",\n \"NR-07\": \"Buada\",\n \"NR-08\": \"Denigomodu\",\n \"NR-09\": \"Ewa\",\n \"NR-10\": \"Ijuw\",\n \"NR-11\": \"Meneng\",\n \"NR-12\": \"Nibok\",\n \"NR-13\": \"Uaboe\",\n \"NR-14\": \"Yaren\",\n \"NP-P3\": \"Bāgmatī\",\n \"NP-P4\": \"Gaṇḍakī\",\n \"NP-P6\": \"Karṇālī\",\n \"NP-P1\": \"Koshī\",\n \"NP-P5\": \"Lumbinī\",\n \"NP-P2\": \"Madhesh\",\n \"NP-P7\": \"Sudūrpashchim\",\n \"NL-DR\": \"Drenthe\",\n \"NL-FL\": \"Flevoland\",\n \"NL-FR\": \"Fryslânfy\",\n \"NL-GE\": \"Gelderland\",\n \"NL-GR\": \"Groningen\",\n \"NL-LI\": \"Limburg\",\n \"NL-NB\": \"Noord-Brabant\",\n \"NL-NH\": \"Noord-Holland\",\n \"NL-OV\": \"Overijssel\",\n \"NL-UT\": \"Utrecht\",\n \"NL-ZE\": \"Zeeland\",\n \"NL-ZH\": \"Zuid-Holland\",\n \"NZ-AUK\": \"Auckland\",\n \"NZ-BOP\": \"Bay of Plenty\",\n \"NZ-CAN\": \"Canterbury\",\n \"NZ-CIT\": \"Chatham Islands Territory\",\n \"NZ-GIS\": \"Gisborne\",\n \"NZ-WGN\": \"Greater Wellington\",\n \"NZ-HKB\": \"Hawke's Bay\",\n \"NZ-MWT\": \"Manawatū-Whanganui\",\n \"NZ-MBH\": \"Marlborough\",\n \"NZ-NSN\": \"Nelson\",\n \"NZ-NTL\": \"Northland\",\n \"NZ-OTA\": \"Otago\",\n \"NZ-STL\": \"Southland\",\n \"NZ-TKI\": \"Taranaki\",\n \"NZ-TAS\": \"Tasman\",\n \"NZ-WKO\": \"Waikato\",\n \"NZ-WTC\": \"West Coast\",\n \"NI-BO\": \"Boaco\",\n \"NI-CA\": \"Carazo\",\n \"NI-CI\": \"Chinandega\",\n \"NI-CO\": \"Chontales\",\n \"NI-AN\": \"Costa Caribe Norte\",\n \"NI-AS\": \"Costa Caribe Sur\",\n \"NI-ES\": \"Estelí\",\n \"NI-GR\": \"Granada\",\n \"NI-JI\": \"Jinotega\",\n \"NI-LE\": \"León\",\n \"NI-MD\": \"Madriz\",\n \"NI-MN\": \"Managua\",\n \"NI-MS\": \"Masaya\",\n \"NI-MT\": \"Matagalpa\",\n \"NI-NS\": \"Nueva Segovia\",\n \"NI-SJ\": \"Río San Juan\",\n \"NI-RI\": \"Rivas\",\n \"NE-1\": \"Agadez\",\n \"NE-2\": \"Diffa\",\n \"NE-3\": \"Dosso\",\n \"NE-4\": \"Maradi\",\n \"NE-8\": \"Niamey\",\n \"NE-5\": \"Tahoua\",\n \"NE-6\": \"Tillabéri\",\n \"NE-7\": \"Zinder\",\n \"NG-AB\": \"Abia\",\n \"NG-FC\": \"Abuja Federal Capital Territory\",\n \"NG-AD\": \"Adamawa\",\n \"NG-AK\": \"Akwa Ibom\",\n \"NG-AN\": \"Anambra\",\n \"NG-BA\": \"Bauchi\",\n \"NG-BY\": \"Bayelsa\",\n \"NG-BE\": \"Benue\",\n \"NG-BO\": \"Borno\",\n \"NG-CR\": \"Cross River\",\n \"NG-DE\": \"Delta\",\n \"NG-EB\": \"Ebonyi\",\n \"NG-ED\": \"Edo\",\n \"NG-EK\": \"Ekiti\",\n \"NG-EN\": \"Enugu\",\n \"NG-GO\": \"Gombe\",\n \"NG-IM\": \"Imo\",\n \"NG-JI\": \"Jigawa\",\n \"NG-KD\": \"Kaduna\",\n \"NG-KN\": \"Kano\",\n \"NG-KT\": \"Katsina\",\n \"NG-KE\": \"Kebbi\",\n \"NG-KO\": \"Kogi\",\n \"NG-KW\": \"Kwara\",\n \"NG-LA\": \"Lagos\",\n \"NG-NA\": \"Nasarawa\",\n \"NG-NI\": \"Niger\",\n \"NG-OG\": \"Ogun\",\n \"NG-ON\": \"Ondo\",\n \"NG-OS\": \"Osun\",\n \"NG-OY\": \"Oyo\",\n \"NG-PL\": \"Plateau\",\n \"NG-RI\": \"Rivers\",\n \"NG-SO\": \"Sokoto\",\n \"NG-TA\": \"Taraba\",\n \"NG-YO\": \"Yobe\",\n \"NG-ZA\": \"Zamfara\",\n \"MK-801\": \"Aerodrom\",\n \"MK-802\": \"Aračinovo\",\n \"MK-201\": \"Berovo\",\n \"MK-501\": \"Bitola\",\n \"MK-401\": \"Bogdanci\",\n \"MK-601\": \"Bogovinje\",\n \"MK-402\": \"Bosilovo\",\n \"MK-602\": \"Brvenica\",\n \"MK-803\": \"Butel\",\n \"MK-814\": \"Centar\",\n \"MK-313\": \"Centar Župa\",\n \"MK-815\": \"Čair\",\n \"MK-109\": \"Čaška\",\n \"MK-210\": \"Češinovo-Obleševo\",\n \"MK-816\": \"Čučer-Sandevo\",\n \"MK-303\": \"Debar\",\n \"MK-304\": \"Debrca\",\n \"MK-203\": \"Delčevo\",\n \"MK-502\": \"Demir Hisar\",\n \"MK-103\": \"Demir Kapija\",\n \"MK-406\": \"Dojran\",\n \"MK-503\": \"Dolneni\",\n \"MK-804\": \"Gazi Baba\",\n \"MK-405\": \"Gevgelija\",\n \"MK-805\": \"Gjorče Petrov\",\n \"MK-604\": \"Gostivar\",\n \"MK-102\": \"Gradsko\",\n \"MK-807\": \"Ilinden\",\n \"MK-606\": \"Jegunovce\",\n \"MK-205\": \"Karbinci\",\n \"MK-808\": \"Karpoš\",\n \"MK-104\": \"Kavadarci\",\n \"MK-307\": \"Kičevo\",\n \"MK-809\": \"Kisela Voda\",\n \"MK-206\": \"Kočani\",\n \"MK-407\": \"Konče\",\n \"MK-701\": \"Kratovo\",\n \"MK-702\": \"Kriva Palanka\",\n \"MK-504\": \"Krivogaštani\",\n \"MK-505\": \"Kruševo\",\n \"MK-703\": \"Kumanovo\",\n \"MK-704\": \"Lipkovo\",\n \"MK-105\": \"Lozovo\",\n \"MK-207\": \"Makedonska Kamenica\",\n \"MK-308\": \"Makedonski Brod\",\n \"MK-607\": \"Mavrovo i Rostuše\",\n \"MK-506\": \"Mogila\",\n \"MK-106\": \"Negotino\",\n \"MK-507\": \"Novaci\",\n \"MK-408\": \"Novo Selo\",\n \"MK-310\": \"Ohrid\",\n \"MK-208\": \"Pehčevo\",\n \"MK-810\": \"Petrovec\",\n \"MK-311\": \"Plasnica\",\n \"MK-508\": \"Prilep\",\n \"MK-209\": \"Probištip\",\n \"MK-409\": \"Radoviš\",\n \"MK-705\": \"Rankovce\",\n \"MK-509\": \"Resen\",\n \"MK-107\": \"Rosoman\",\n \"MK-811\": \"Saraj\",\n \"MK-812\": \"Sopište\",\n \"MK-706\": \"Staro Nagoričane\",\n \"MK-312\": \"Struga\",\n \"MK-410\": \"Strumica\",\n \"MK-813\": \"Studeničani\",\n \"MK-108\": \"Sveti Nikole\",\n \"MK-211\": \"Štip\",\n \"MK-817\": \"Šuto Orizari\",\n \"MK-608\": \"Tearce\",\n \"MK-609\": \"Tetovo\",\n \"MK-403\": \"Valandovo\",\n \"MK-404\": \"Vasilevo\",\n \"MK-101\": \"Veles\",\n \"MK-301\": \"Vevčani\",\n \"MK-202\": \"Vinica\",\n \"MK-603\": \"Vrapčište\",\n \"MK-806\": \"Zelenikovo\",\n \"MK-204\": \"Zrnovci\",\n \"MK-605\": \"Želino\",\n \"NO-42\": \"Agder\",\n \"NO-34\": \"Innlandet\",\n \"NO-22\": \"Jan Mayen\",\n \"NO-15\": \"Møre og Romsdal\",\n \"NO-18\": \"Nordland\",\n \"NO-03\": \"Oslo\",\n \"NO-11\": \"Rogaland\",\n \"NO-21\": \"Svalbard\",\n \"NO-54\": \"Troms og Finnmarksefkv\",\n \"NO-50\": \"Trøndelagsma\",\n \"NO-38\": \"Vestfold og Telemark\",\n \"NO-46\": \"Vestland\",\n \"NO-30\": \"Viken\",\n \"OM-DA\": \"Ad Dākhilīyah\",\n \"OM-BU\": \"Al Buraymī\",\n \"OM-WU\": \"Al Wusţá\",\n \"OM-ZA\": \"Az̧ Z̧āhirah\",\n \"OM-BJ\": \"Janūb al Bāţinah\",\n \"OM-SJ\": \"Janūb ash Sharqīyah\",\n \"OM-MA\": \"Masqaţ\",\n \"OM-MU\": \"Musandam\",\n \"OM-BS\": \"Shamāl al Bāţinah\",\n \"OM-SS\": \"Shamāl ash Sharqīyah\",\n \"OM-ZU\": \"Z̧ufār\",\n \"PK-JK\": \"Āzād Jammūñ o Kashmīr\",\n \"PK-BA\": \"Balōchistān\",\n \"PK-GB\": \"Gilgit-Baltistān\",\n \"PK-IS\": \"Islāmābād\",\n \"PK-KP\": \"Khaībar Pakhtūnkhwā\",\n \"PK-PB\": \"Panjāb\",\n \"PK-SD\": \"Sindh\",\n \"PW-002\": \"Aimeliik\",\n \"PW-004\": \"Airai\",\n \"PW-010\": \"Angaur\",\n \"PW-050\": \"Hatohobei\",\n \"PW-100\": \"Kayangel\",\n \"PW-150\": \"Koror\",\n \"PW-212\": \"Melekeok\",\n \"PW-214\": \"Ngaraard\",\n \"PW-218\": \"Ngarchelong\",\n \"PW-222\": \"Ngardmau\",\n \"PW-224\": \"Ngatpang\",\n \"PW-226\": \"Ngchesar\",\n \"PW-227\": \"Ngeremlengui\",\n \"PW-228\": \"Ngiwal\",\n \"PW-350\": \"Peleliu\",\n \"PW-370\": \"Sonsorol\",\n \"PS-BTH\": \"Bayt Laḩm\",\n \"PS-DEB\": \"Dayr al Balaḩ\",\n \"PS-GZA\": \"Ghazzah\",\n \"PS-HBN\": \"Al Khalīl\",\n \"PS-JEN\": \"Janīn\",\n \"PS-JRH\": \"Arīḩā wal Aghwār\",\n \"PS-JEM\": \"Al Quds\",\n \"PS-KYS\": \"Khān Yūnis\",\n \"PS-NBS\": \"Nāblus\",\n \"PS-NGZ\": \"Shamāl Ghazzah\",\n \"PS-QQA\": \"Qalqīlyah\",\n \"PS-RFH\": \"Rafaḩ\",\n \"PS-RBH\": \"Rām Allāh wal Bīrah\",\n \"PS-SLT\": \"Salfīt\",\n \"PS-TBS\": \"Ţūbās\",\n \"PS-TKM\": \"Ţūlkarm\",\n \"PA-1\": \"Bocas del Toro\",\n \"PA-4\": \"Chiriquí\",\n \"PA-2\": \"Coclé\",\n \"PA-3\": \"Colón\",\n \"PA-5\": \"Darién\",\n \"PA-EM\": \"Emberá\",\n \"PA-KY\": \"Guna Yala\",\n \"PA-6\": \"Herrera\",\n \"PA-7\": \"Los Santos\",\n \"PA-NT\": \"Naso Tjër Di\",\n \"PA-NB\": \"Ngäbe-Buglé\",\n \"PA-8\": \"Panamá\",\n \"PA-10\": \"Panamá Oeste\",\n \"PA-9\": \"Veraguas\",\n \"PG-NSB\": \"Bougainville\",\n \"PG-CPM\": \"Central\",\n \"PG-CPK\": \"Chimbu\",\n \"PG-EBR\": \"East New Britain\",\n \"PG-ESW\": \"East Sepik\",\n \"PG-EHG\": \"Eastern Highlands\",\n \"PG-EPW\": \"Enga\",\n \"PG-GPK\": \"Gulf\",\n \"PG-HLA\": \"Hela\",\n \"PG-JWK\": \"Jiwaka\",\n \"PG-MPM\": \"Madang\",\n \"PG-MRL\": \"Manus\",\n \"PG-MBA\": \"Milne Bay\",\n \"PG-MPL\": \"Morobe\",\n \"PG-NCD\": \"National Capital District\",\n \"PG-NIK\": \"New Ireland\",\n \"PG-NPP\": \"Northern\",\n \"PG-SHM\": \"Southern Highlands\",\n \"PG-WBK\": \"West New Britain\",\n \"PG-SAN\": \"West Sepik\",\n \"PG-WPD\": \"Western\",\n \"PG-WHM\": \"Western Highlands\",\n \"PY-16\": \"Alto Paraguay\",\n \"PY-10\": \"Alto Paraná\",\n \"PY-13\": \"Amambay\",\n \"PY-ASU\": \"Asunción\",\n \"PY-19\": \"Boquerón\",\n \"PY-5\": \"Caaguazú\",\n \"PY-6\": \"Caazapá\",\n \"PY-14\": \"Canindeyú\",\n \"PY-11\": \"Central\",\n \"PY-1\": \"Concepción\",\n \"PY-3\": \"Cordillera\",\n \"PY-4\": \"Guairá\",\n \"PY-7\": \"Itapúa\",\n \"PY-8\": \"Misiones\",\n \"PY-12\": \"Ñeembucú\",\n \"PY-9\": \"Paraguarí\",\n \"PY-15\": \"Presidente Hayes\",\n \"PY-2\": \"San Pedro\",\n \"PE-AMA\": \"Amazonas\",\n \"PE-ANC\": \"Ancash\",\n \"PE-APU\": \"Apurímac\",\n \"PE-ARE\": \"Arequipa\",\n \"PE-AYA\": \"Ayacucho\",\n \"PE-CAJ\": \"Cajamarca\",\n \"PE-CUS\": \"Cusco\",\n \"PE-CAL\": \"El Callao\",\n \"PE-HUV\": \"Huancavelica\",\n \"PE-HUC\": \"Huánuco\",\n \"PE-ICA\": \"Ica\",\n \"PE-JUN\": \"Junín\",\n \"PE-LAL\": \"La Libertad\",\n \"PE-LAM\": \"Lambayeque\",\n \"PE-LIM\": \"Lima\",\n \"PE-LOR\": \"Loreto\",\n \"PE-MDD\": \"Madre de Dios\",\n \"PE-MOQ\": \"Moquegua\",\n \"PE-LMA\": \"Municipalidad Metropolitana de Lima\",\n \"PE-PAS\": \"Pasco\",\n \"PE-PIU\": \"Piura\",\n \"PE-PUN\": \"Puno\",\n \"PE-SAM\": \"San Martín\",\n \"PE-TAC\": \"Tacna\",\n \"PE-TUM\": \"Tumbes\",\n \"PE-UCA\": \"Ucayali\",\n \"PH-14\": \"Autonomous Region in Muslim Mindanao\",\n \"PH-05\": \"Bicol\",\n \"PH-02\": \"Cagayan Valley\",\n \"PH-40\": \"Calabarzon\",\n \"PH-13\": \"Caraga\",\n \"PH-03\": \"Central Luzon\",\n \"PH-07\": \"Central Visayas\",\n \"PH-15\": \"Cordillera Administrative Region\",\n \"PH-11\": \"Davao\",\n \"PH-08\": \"Eastern Visayas\",\n \"PH-01\": \"Ilocos\",\n \"PH-41\": \"Mimaropa\",\n \"PH-00\": \"National Capital Region\",\n \"PH-10\": \"Northern Mindanao\",\n \"PH-12\": \"Soccsksargen\",\n \"PH-06\": \"Western Visayas\",\n \"PH-09\": \"Zamboanga Peninsula\",\n \"PL-02\": \"Dolnośląskie\",\n \"PL-04\": \"Kujawsko-Pomorskie\",\n \"PL-06\": \"Lubelskie\",\n \"PL-08\": \"Lubuskie\",\n \"PL-10\": \"Łódzkie\",\n \"PL-12\": \"Małopolskie\",\n \"PL-14\": \"Mazowieckie\",\n \"PL-16\": \"Opolskie\",\n \"PL-18\": \"Podkarpackie\",\n \"PL-20\": \"Podlaskie\",\n \"PL-22\": \"Pomorskie\",\n \"PL-24\": \"Śląskie\",\n \"PL-26\": \"Świętokrzyskie\",\n \"PL-28\": \"Warmińsko-Mazurskie\",\n \"PL-30\": \"Wielkopolskie\",\n \"PL-32\": \"Zachodniopomorskie\",\n \"PT-01\": \"Aveiro\",\n \"PT-02\": \"Beja\",\n \"PT-03\": \"Braga\",\n \"PT-04\": \"Bragança\",\n \"PT-05\": \"Castelo Branco\",\n \"PT-06\": \"Coimbra\",\n \"PT-07\": \"Évora\",\n \"PT-08\": \"Faro\",\n \"PT-09\": \"Guarda\",\n \"PT-10\": \"Leiria\",\n \"PT-11\": \"Lisboa\",\n \"PT-12\": \"Portalegre\",\n \"PT-13\": \"Porto\",\n \"PT-30\": \"Região Autónoma da Madeira\",\n \"PT-20\": \"Região Autónoma dos Açores\",\n \"PT-14\": \"Santarém\",\n \"PT-15\": \"Setúbal\",\n \"PT-16\": \"Viana do Castelo\",\n \"PT-17\": \"Vila Real\",\n \"PT-18\": \"Viseu\",\n \"QA-DA\": \"Ad Dawḩah\",\n \"QA-KH\": \"Al Khawr wa adh Dhakhīrah\",\n \"QA-WA\": \"Al Wakrah\",\n \"QA-RA\": \"Ar Rayyān\",\n \"QA-MS\": \"Ash Shamāl\",\n \"QA-SH\": \"Ash Shīḩānīyah\",\n \"QA-ZA\": \"Az̧ Z̧a‘āyin\",\n \"QA-US\": \"Umm Şalāl\",\n \"RO-AB\": \"Alba\",\n \"RO-AR\": \"Arad\",\n \"RO-AG\": \"Argeș\",\n \"RO-BC\": \"Bacău\",\n \"RO-BH\": \"Bihor\",\n \"RO-BN\": \"Bistrița-Năsăud\",\n \"RO-BT\": \"Botoșani\",\n \"RO-BV\": \"Brașov\",\n \"RO-BR\": \"Brăila\",\n \"RO-B\": \"București\",\n \"RO-BZ\": \"Buzău\",\n \"RO-CS\": \"Caraș-Severin\",\n \"RO-CL\": \"Călărași\",\n \"RO-CJ\": \"Cluj\",\n \"RO-CT\": \"Constanța\",\n \"RO-CV\": \"Covasna\",\n \"RO-DB\": \"Dâmbovița\",\n \"RO-DJ\": \"Dolj\",\n \"RO-GL\": \"Galați\",\n \"RO-GR\": \"Giurgiu\",\n \"RO-GJ\": \"Gorj\",\n \"RO-HR\": \"Harghita\",\n \"RO-HD\": \"Hunedoara\",\n \"RO-IL\": \"Ialomița\",\n \"RO-IS\": \"Iași\",\n \"RO-IF\": \"Ilfov\",\n \"RO-MM\": \"Maramureș\",\n \"RO-MH\": \"Mehedinți\",\n \"RO-MS\": \"Mureș\",\n \"RO-NT\": \"Neamț\",\n \"RO-OT\": \"Olt\",\n \"RO-PH\": \"Prahova\",\n \"RO-SM\": \"Satu Mare\",\n \"RO-SJ\": \"Sălaj\",\n \"RO-SB\": \"Sibiu\",\n \"RO-SV\": \"Suceava\",\n \"RO-TR\": \"Teleorman\",\n \"RO-TM\": \"Timiș\",\n \"RO-TL\": \"Tulcea\",\n \"RO-VS\": \"Vaslui\",\n \"RO-VL\": \"Vâlcea\",\n \"RO-VN\": \"Vrancea\",\n \"RU-AD\": \"Adygeya\",\n \"RU-AL\": \"Altay\",\n \"RU-ALT\": \"Altayskiy kray\",\n \"RU-AMU\": \"Amurskaya oblast'\",\n \"RU-ARK\": \"Arkhangel'skaya oblast'\",\n \"RU-AST\": \"Astrakhanskaya oblast'\",\n \"RU-BA\": \"Bashkortostan\",\n \"RU-BEL\": \"Belgorodskaya oblast'\",\n \"RU-BRY\": \"Bryanskaya oblast'\",\n \"RU-BU\": \"Buryatiya\",\n \"RU-CE\": \"Chechenskaya Respublika\",\n \"RU-CHE\": \"Chelyabinskaya oblast'\",\n \"RU-CHU\": \"Chukotskiy avtonomnyy okrug\",\n \"RU-CU\": \"Chuvashskaya Respublika\",\n \"RU-DA\": \"Dagestan\",\n \"RU-IN\": \"Ingushetiya\",\n \"RU-IRK\": \"Irkutskaya oblast'\",\n \"RU-IVA\": \"Ivanovskaya oblast'\",\n \"RU-KB\": \"Kabardino-BalkarskayaRespublika\",\n \"RU-KGD\": \"Kaliningradskaya oblast'\",\n \"RU-KL\": \"Kalmykiya\",\n \"RU-KLU\": \"Kaluzhskaya oblast'\",\n \"RU-KAM\": \"Kamchatskiy kray\",\n \"RU-KC\": \"Karachayevo-CherkesskayaRespublika\",\n \"RU-KR\": \"Kareliya\",\n \"RU-KEM\": \"Kemerovskaya oblast'\",\n \"RU-KHA\": \"Khabarovskiy kray\",\n \"RU-KK\": \"Khakasiya\",\n \"RU-KHM\": \"Khanty-Mansiyskiyavtonomnyy okrug\",\n \"RU-KIR\": \"Kirovskaya oblast'\",\n \"RU-KO\": \"Komi\",\n \"RU-KOS\": \"Kostromskaya oblast'\",\n \"RU-KDA\": \"Krasnodarskiy kray\",\n \"RU-KYA\": \"Krasnoyarskiy kray\",\n \"RU-KGN\": \"Kurganskaya oblast'\",\n \"RU-KRS\": \"Kurskaya oblast'\",\n \"RU-LEN\": \"Leningradskayaoblast'\",\n \"RU-LIP\": \"Lipetskaya oblast'\",\n \"RU-MAG\": \"Magadanskaya oblast'\",\n \"RU-ME\": \"Mariy El\",\n \"RU-MO\": \"Mordoviya\",\n \"RU-MOS\": \"Moskovskaya oblast'\",\n \"RU-MOW\": \"Moskva\",\n \"RU-MUR\": \"Murmanskaya oblast'\",\n \"RU-NEN\": \"Nenetskiyavtonomnyy okrug\",\n \"RU-NIZ\": \"Nizhegorodskaya oblast'\",\n \"RU-NGR\": \"Novgorodskaya oblast'\",\n \"RU-NVS\": \"Novosibirskayaoblast'\",\n \"RU-OMS\": \"Omskaya oblast'\",\n \"RU-ORE\": \"Orenburgskaya oblast'\",\n \"RU-ORL\": \"Orlovskaya oblast'\",\n \"RU-PNZ\": \"Penzenskaya oblast'\",\n \"RU-PER\": \"Permskiy kray\",\n \"RU-PRI\": \"Primorskiy kray\",\n \"RU-PSK\": \"Pskovskaya oblast'\",\n \"RU-ROS\": \"Rostovskaya oblast'\",\n \"RU-RYA\": \"Ryazanskaya oblast'\",\n \"RU-SA\": \"Saha\",\n \"RU-SAK\": \"Sakhalinskaya oblast'\",\n \"RU-SAM\": \"Samarskaya oblast'\",\n \"RU-SPE\": \"Sankt-Peterburg\",\n \"RU-SAR\": \"Saratovskaya oblast'\",\n \"RU-SE\": \"Severnaya Osetiya\",\n \"RU-SMO\": \"Smolenskaya oblast'\",\n \"RU-STA\": \"Stavropol'skiy kray\",\n \"RU-SVE\": \"Sverdlovskaya oblast'\",\n \"RU-TAM\": \"Tambovskaya oblast'\",\n \"RU-TA\": \"Tatarstan\",\n \"RU-TOM\": \"Tomskaya oblast'\",\n \"RU-TUL\": \"Tul'skaya oblast'\",\n \"RU-TVE\": \"Tverskaya oblast'\",\n \"RU-TYU\": \"Tyumenskaya oblast'\",\n \"RU-TY\": \"Tyva\",\n \"RU-UD\": \"Udmurtskaya Respublika\",\n \"RU-ULY\": \"Ul'yanovskaya oblast'\",\n \"RU-VLA\": \"Vladimirskayaoblast'\",\n \"RU-VGG\": \"Volgogradskayaoblast'\",\n \"RU-VLG\": \"Vologodskaya oblast'\",\n \"RU-VOR\": \"Voronezhskaya oblast'\",\n \"RU-YAN\": \"Yamalo-Nenetskiyavtonomnyy okrug\",\n \"RU-YAR\": \"Yaroslavskaya oblast'\",\n \"RU-YEV\": \"Yevreyskaya avtonomnaya oblast'\",\n \"RU-ZAB\": \"Zabaykal'skiy kray\",\n \"RW-01\": \"City of Kigali\",\n \"RW-02\": \"Eastern\",\n \"RW-03\": \"Northern\",\n \"RW-05\": \"Southern\",\n \"RW-04\": \"Western\",\n \"SH-AC\": \"Ascension\",\n \"SH-HL\": \"Saint Helena\",\n \"SH-TA\": \"Tristan da Cunha\",\n \"KN-K\": \"Saint Kitts\",\n \"KN-N\": \"Nevis\",\n \"LC-01\": \"Anse la Raye\",\n \"LC-12\": \"Canaries\",\n \"LC-02\": \"Castries\",\n \"LC-03\": \"Choiseul\",\n \"LC-05\": \"Dennery\",\n \"LC-06\": \"Gros Islet\",\n \"LC-07\": \"Laborie\",\n \"LC-08\": \"Micoud\",\n \"LC-10\": \"Soufrière\",\n \"LC-11\": \"Vieux Fort\",\n \"VC-01\": \"Charlotte\",\n \"VC-06\": \"Grenadines\",\n \"VC-02\": \"Saint Andrew\",\n \"VC-03\": \"Saint David\",\n \"VC-04\": \"Saint George\",\n \"VC-05\": \"Saint Patrick\",\n \"WS-AA\": \"A'ana\",\n \"WS-AL\": \"Aiga-i-le-Tai\",\n \"WS-AT\": \"Atua\",\n \"WS-FA\": \"Fa'asaleleaga\",\n \"WS-GE\": \"Gaga'emauga\",\n \"WS-GI\": \"Gagaifomauga\",\n \"WS-PA\": \"Palauli\",\n \"WS-SA\": \"Satupa'itea\",\n \"WS-TU\": \"Tuamasaga\",\n \"WS-VF\": \"Va'a-o-Fonoti\",\n \"WS-VS\": \"Vaisigano\",\n \"SM-01\": \"Acquaviva\",\n \"SM-06\": \"Borgo Maggiore\",\n \"SM-02\": \"Chiesanuova\",\n \"SM-07\": \"Città di San Marino\",\n \"SM-03\": \"Domagnano\",\n \"SM-04\": \"Faetano\",\n \"SM-05\": \"Fiorentino\",\n \"SM-08\": \"Montegiardino\",\n \"SM-09\": \"Serravalle\",\n \"ST-01\": \"Água Grande\",\n \"ST-02\": \"Cantagalo\",\n \"ST-03\": \"Caué\",\n \"ST-04\": \"Lembá\",\n \"ST-05\": \"Lobata\",\n \"ST-06\": \"Mé-Zóchi\",\n \"ST-P\": \"Príncipe\",\n \"SA-14\": \"'Asīr\",\n \"SA-11\": \"Al Bāḩah\",\n \"SA-08\": \"Al Ḩudūd ash Shamālīyah\",\n \"SA-12\": \"Al Jawf\",\n \"SA-03\": \"Al Madīnah al Munawwarah\",\n \"SA-05\": \"Al Qaşīm\",\n \"SA-01\": \"Ar Riyāḑ\",\n \"SA-04\": \"Ash Sharqīyah\",\n \"SA-06\": \"Ḩā'il\",\n \"SA-09\": \"Jāzān\",\n \"SA-02\": \"Makkah al Mukarramah\",\n \"SA-10\": \"Najrān\",\n \"SA-07\": \"Tabūk\",\n \"SN-DK\": \"Dakar\",\n \"SN-DB\": \"Diourbel\",\n \"SN-FK\": \"Fatick\",\n \"SN-KA\": \"Kaffrine\",\n \"SN-KL\": \"Kaolack\",\n \"SN-KE\": \"Kédougou\",\n \"SN-KD\": \"Kolda\",\n \"SN-LG\": \"Louga\",\n \"SN-MT\": \"Matam\",\n \"SN-SL\": \"Saint-Louis\",\n \"SN-SE\": \"Sédhiou\",\n \"SN-TC\": \"Tambacounda\",\n \"SN-TH\": \"Thiès\",\n \"SN-ZG\": \"Ziguinchor\",\n \"SC-01\": \"Anse aux Pins\",\n \"SC-02\": \"Anse Boileau\",\n \"SC-03\": \"Anse Etoile\",\n \"SC-05\": \"Anse Royale\",\n \"SC-04\": \"Au Cap\",\n \"SC-06\": \"Baie Lazare\",\n \"SC-07\": \"Baie Sainte Anne\",\n \"SC-08\": \"Beau Vallon\",\n \"SC-09\": \"Bel Air\",\n \"SC-10\": \"Bel Ombre\",\n \"SC-11\": \"Cascade\",\n \"SC-16\": \"English River\",\n \"SC-12\": \"Glacis\",\n \"SC-13\": \"Grand Anse Mahe\",\n \"SC-14\": \"Grand Anse Praslin\",\n \"SC-26\": \"Ile Perseverance I\",\n \"SC-27\": \"Ile Perseverance II\",\n \"SC-15\": \"La Digue\",\n \"SC-24\": \"Les Mamelles\",\n \"SC-17\": \"Mont Buxton\",\n \"SC-18\": \"Mont Fleuri\",\n \"SC-19\": \"Plaisance\",\n \"SC-20\": \"Pointe Larue\",\n \"SC-21\": \"Port Glaud\",\n \"SC-25\": \"Roche Caiman\",\n \"SC-22\": \"Saint Louis\",\n \"SC-23\": \"Takamaka\",\n \"SL-E\": \"Eastern\",\n \"SL-NW\": \"North Western\",\n \"SL-N\": \"Northern\",\n \"SL-S\": \"Southern\",\n \"SL-W\": \"Western Area\",\n \"SG-01\": \"Central Singapore\",\n \"SG-02\": \"North East\",\n \"SG-03\": \"North West\",\n \"SG-04\": \"South East\",\n \"SG-05\": \"South West\",\n \"SK-BC\": \"Banskobystrický kraj\",\n \"SK-BL\": \"Bratislavský kraj\",\n \"SK-KI\": \"Košický kraj\",\n \"SK-NI\": \"Nitriansky kraj\",\n \"SK-PV\": \"Prešovský kraj\",\n \"SK-TC\": \"Trenčiansky kraj\",\n \"SK-TA\": \"Trnavský kraj\",\n \"SK-ZI\": \"Žilinský kraj\",\n \"SI-001\": \"Ajdovščina\",\n \"SI-213\": \"Ankaran\",\n \"SI-195\": \"Apače\",\n \"SI-002\": \"Beltinci\",\n \"SI-148\": \"Benedikt\",\n \"SI-149\": \"Bistrica ob Sotli\",\n \"SI-003\": \"Bled\",\n \"SI-150\": \"Bloke\",\n \"SI-004\": \"Bohinj\",\n \"SI-005\": \"Borovnica\",\n \"SI-006\": \"Bovec\",\n \"SI-151\": \"Braslovče\",\n \"SI-007\": \"Brda\",\n \"SI-008\": \"Brezovica\",\n \"SI-009\": \"Brežice\",\n \"SI-152\": \"Cankova\",\n \"SI-011\": \"Celje\",\n \"SI-012\": \"Cerklje na Gorenjskem\",\n \"SI-013\": \"Cerknica\",\n \"SI-014\": \"Cerkno\",\n \"SI-153\": \"Cerkvenjak\",\n \"SI-196\": \"Cirkulane\",\n \"SI-015\": \"Črenšovci\",\n \"SI-016\": \"Črna na Koroškem\",\n \"SI-017\": \"Črnomelj\",\n \"SI-018\": \"Destrnik\",\n \"SI-019\": \"Divača\",\n \"SI-154\": \"Dobje\",\n \"SI-020\": \"Dobrepolje\",\n \"SI-155\": \"Dobrna\",\n \"SI-021\": \"Dobrova-Polhov Gradec\",\n \"SI-156\": \"Dobrovnik\",\n \"SI-022\": \"Dol pri Ljubljani\",\n \"SI-157\": \"Dolenjske Toplice\",\n \"SI-023\": \"Domžale\",\n \"SI-024\": \"Dornava\",\n \"SI-025\": \"Dravograd\",\n \"SI-026\": \"Duplek\",\n \"SI-027\": \"Gorenja vas-Poljane\",\n \"SI-028\": \"Gorišnica\",\n \"SI-207\": \"Gorje\",\n \"SI-029\": \"Gornja Radgona\",\n \"SI-030\": \"Gornji Grad\",\n \"SI-031\": \"Gornji Petrovci\",\n \"SI-158\": \"Grad\",\n \"SI-032\": \"Grosuplje\",\n \"SI-159\": \"Hajdina\",\n \"SI-160\": \"Hoče-Slivnica\",\n \"SI-161\": \"Hodoš\",\n \"SI-162\": \"Horjul\",\n \"SI-034\": \"Hrastnik\",\n \"SI-035\": \"Hrpelje-Kozina\",\n \"SI-036\": \"Idrija\",\n \"SI-037\": \"Ig\",\n \"SI-038\": \"Ilirska Bistrica\",\n \"SI-039\": \"Ivančna Gorica\",\n \"SI-040\": \"Izola\",\n \"SI-041\": \"Jesenice\",\n \"SI-163\": \"Jezersko\",\n \"SI-042\": \"Juršinci\",\n \"SI-043\": \"Kamnik\",\n \"SI-044\": \"Kanal ob Soči\",\n \"SI-045\": \"Kidričevo\",\n \"SI-046\": \"Kobarid\",\n \"SI-047\": \"Kobilje\",\n \"SI-048\": \"Kočevje\",\n \"SI-049\": \"Komen\",\n \"SI-164\": \"Komenda\",\n \"SI-050\": \"Koper\",\n \"SI-197\": \"Kostanjevica na Krki\",\n \"SI-165\": \"Kostel\",\n \"SI-051\": \"Kozje\",\n \"SI-052\": \"Kranj\",\n \"SI-053\": \"Kranjska Gora\",\n \"SI-166\": \"Križevci\",\n \"SI-054\": \"Krško\",\n \"SI-055\": \"Kungota\",\n \"SI-056\": \"Kuzma\",\n \"SI-057\": \"Laško\",\n \"SI-058\": \"Lenart\",\n \"SI-059\": \"Lendava\",\n \"SI-060\": \"Litija\",\n \"SI-061\": \"Ljubljana\",\n \"SI-062\": \"Ljubno\",\n \"SI-063\": \"Ljutomer\",\n \"SI-208\": \"Log-Dragomer\",\n \"SI-064\": \"Logatec\",\n \"SI-065\": \"Loška dolina\",\n \"SI-066\": \"Loški Potok\",\n \"SI-167\": \"Lovrenc na Pohorju\",\n \"SI-067\": \"Luče\",\n \"SI-068\": \"Lukovica\",\n \"SI-069\": \"Majšperk\",\n \"SI-198\": \"Makole\",\n \"SI-070\": \"Maribor\",\n \"SI-168\": \"Markovci\",\n \"SI-071\": \"Medvode\",\n \"SI-072\": \"Mengeš\",\n \"SI-073\": \"Metlika\",\n \"SI-074\": \"Mežica\",\n \"SI-169\": \"Miklavž na Dravskem polju\",\n \"SI-075\": \"Miren-Kostanjevica\",\n \"SI-212\": \"Mirna\",\n \"SI-170\": \"Mirna Peč\",\n \"SI-076\": \"Mislinja\",\n \"SI-199\": \"Mokronog-Trebelno\",\n \"SI-077\": \"Moravče\",\n \"SI-078\": \"Moravske Toplice\",\n \"SI-079\": \"Mozirje\",\n \"SI-080\": \"Murska Sobota\",\n \"SI-081\": \"Muta\",\n \"SI-082\": \"Naklo\",\n \"SI-083\": \"Nazarje\",\n \"SI-084\": \"Nova Gorica\",\n \"SI-085\": \"Novo Mesto\",\n \"SI-086\": \"Odranci\",\n \"SI-171\": \"Oplotnica\",\n \"SI-087\": \"Ormož\",\n \"SI-088\": \"Osilnica\",\n \"SI-089\": \"Pesnica\",\n \"SI-090\": \"Piran\",\n \"SI-091\": \"Pivka\",\n \"SI-092\": \"Podčetrtek\",\n \"SI-172\": \"Podlehnik\",\n \"SI-093\": \"Podvelka\",\n \"SI-200\": \"Poljčane\",\n \"SI-173\": \"Polzela\",\n \"SI-094\": \"Postojna\",\n \"SI-174\": \"Prebold\",\n \"SI-095\": \"Preddvor\",\n \"SI-175\": \"Prevalje\",\n \"SI-096\": \"Ptuj\",\n \"SI-097\": \"Puconci\",\n \"SI-098\": \"Rače-Fram\",\n \"SI-099\": \"Radeče\",\n \"SI-100\": \"Radenci\",\n \"SI-101\": \"Radlje ob Dravi\",\n \"SI-102\": \"Radovljica\",\n \"SI-103\": \"Ravne na Koroškem\",\n \"SI-176\": \"Razkrižje\",\n \"SI-209\": \"Rečica ob Savinji\",\n \"SI-201\": \"Renče-Vogrsko\",\n \"SI-104\": \"Ribnica\",\n \"SI-177\": \"Ribnica na Pohorju\",\n \"SI-106\": \"Rogaška Slatina\",\n \"SI-105\": \"Rogašovci\",\n \"SI-107\": \"Rogatec\",\n \"SI-108\": \"Ruše\",\n \"SI-178\": \"Selnica ob Dravi\",\n \"SI-109\": \"Semič\",\n \"SI-110\": \"Sevnica\",\n \"SI-111\": \"Sežana\",\n \"SI-112\": \"Slovenj Gradec\",\n \"SI-113\": \"Slovenska Bistrica\",\n \"SI-114\": \"Slovenske Konjice\",\n \"SI-179\": \"Sodražica\",\n \"SI-180\": \"Solčava\",\n \"SI-202\": \"Središče ob Dravi\",\n \"SI-115\": \"Starše\",\n \"SI-203\": \"Straža\",\n \"SI-181\": \"Sveta Ana\",\n \"SI-204\": \"Sveta Trojica v Slovenskih goricah\",\n \"SI-182\": \"Sveti Andraž v Slovenskih goricah\",\n \"SI-116\": \"Sveti Jurij ob Ščavnici\",\n \"SI-210\": \"Sveti Jurij v Slovenskih goricah\",\n \"SI-205\": \"Sveti Tomaž\",\n \"SI-033\": \"Šalovci\",\n \"SI-183\": \"Šempeter-Vrtojba\",\n \"SI-117\": \"Šenčur\",\n \"SI-118\": \"Šentilj\",\n \"SI-119\": \"Šentjernej\",\n \"SI-120\": \"Šentjur\",\n \"SI-211\": \"Šentrupert\",\n \"SI-121\": \"Škocjan\",\n \"SI-122\": \"Škofja Loka\",\n \"SI-123\": \"Škofljica\",\n \"SI-124\": \"Šmarje pri Jelšah\",\n \"SI-206\": \"Šmarješke Toplice\",\n \"SI-125\": \"Šmartno ob Paki\",\n \"SI-194\": \"Šmartno pri Litiji\",\n \"SI-126\": \"Šoštanj\",\n \"SI-127\": \"Štore\",\n \"SI-184\": \"Tabor\",\n \"SI-010\": \"Tišina\",\n \"SI-128\": \"Tolmin\",\n \"SI-129\": \"Trbovlje\",\n \"SI-130\": \"Trebnje\",\n \"SI-185\": \"Trnovska Vas\",\n \"SI-186\": \"Trzin\",\n \"SI-131\": \"Tržič\",\n \"SI-132\": \"Turnišče\",\n \"SI-133\": \"Velenje\",\n \"SI-187\": \"Velika Polana\",\n \"SI-134\": \"Velike Lašče\",\n \"SI-188\": \"Veržej\",\n \"SI-135\": \"Videm\",\n \"SI-136\": \"Vipava\",\n \"SI-137\": \"Vitanje\",\n \"SI-138\": \"Vodice\",\n \"SI-139\": \"Vojnik\",\n \"SI-189\": \"Vransko\",\n \"SI-140\": \"Vrhnika\",\n \"SI-141\": \"Vuzenica\",\n \"SI-142\": \"Zagorje ob Savi\",\n \"SI-143\": \"Zavrč\",\n \"SI-144\": \"Zreče\",\n \"SI-190\": \"Žalec\",\n \"SI-146\": \"Železniki\",\n \"SI-191\": \"Žetale\",\n \"SI-147\": \"Žiri\",\n \"SI-192\": \"Žirovnica\",\n \"SI-193\": \"Žužemberk\",\n \"SB-CT\": \"Capital Territory\",\n \"SB-CE\": \"Central\",\n \"SB-CH\": \"Choiseul\",\n \"SB-GU\": \"Guadalcanal\",\n \"SB-IS\": \"Isabel\",\n \"SB-MK\": \"Makira-Ulawa\",\n \"SB-ML\": \"Malaita\",\n \"SB-RB\": \"Rennell and Bellona\",\n \"SB-TE\": \"Temotu\",\n \"SB-WE\": \"Western\",\n \"SO-AW\": \"Awdal\",\n \"SO-BK\": \"Bakool\",\n \"SO-BN\": \"Banaadir\",\n \"SO-BR\": \"Bari\",\n \"SO-BY\": \"Bay\",\n \"SO-GA\": \"Galguduud\",\n \"SO-GE\": \"Gedo\",\n \"SO-HI\": \"Hiiraan\",\n \"SO-JD\": \"Jubbada Dhexe\",\n \"SO-JH\": \"Jubbada Hoose\",\n \"SO-MU\": \"Mudug\",\n \"SO-NU\": \"Nugaal\",\n \"SO-SA\": \"Sanaag\",\n \"SO-SD\": \"Shabeellaha Dhexe\",\n \"SO-SH\": \"Shabeellaha Hoose\",\n \"SO-SO\": \"Sool\",\n \"SO-TO\": \"Togdheer\",\n \"SO-WO\": \"Woqooyi Galbeed\",\n \"ZA-EC\": \"Eastern Cape\",\n \"ZA-FS\": \"Free State\",\n \"ZA-GP\": \"Gauteng\",\n \"ZA-KZN\": \"Kwazulu-Natal\",\n \"ZA-LP\": \"Limpopo\",\n \"ZA-MP\": \"Mpumalanga\",\n \"ZA-NW\": \"North-West\",\n \"ZA-NC\": \"Northern Cape\",\n \"ZA-WC\": \"Western Cape\",\n \"ES-AN\": \"Andalucía\",\n \"ES-AR\": \"Aragón\",\n \"ES-AS\": \"Asturias\",\n \"ES-CN\": \"Canarias\",\n \"ES-CB\": \"Cantabria\",\n \"ES-CL\": \"Castilla y León\",\n \"ES-CM\": \"Castilla-La Mancha\",\n \"ES-CT\": \"Catalunya\",\n \"ES-CE\": \"Ceuta\",\n \"ES-EX\": \"Extremadura\",\n \"ES-GA\": \"Galicia\",\n \"ES-IB\": \"Illes Balears\",\n \"ES-RI\": \"La Rioja\",\n \"ES-MD\": \"Madrid\",\n \"ES-ML\": \"Melilla\",\n \"ES-MC\": \"Murcia\",\n \"ES-NC\": \"Navarra\",\n \"ES-PV\": \"País Vasco\",\n \"ES-VC\": \"Valenciana\",\n \"LK-1\": \"Basnāhira paḷāta\",\n \"LK-3\": \"Dakuṇu paḷāta\",\n \"LK-2\": \"Madhyama paḷāta\",\n \"LK-5\": \"Næ̆gĕnahira paḷāta\",\n \"LK-9\": \"Sabaragamuva paḷāta\",\n \"LK-4\": \"Uturu paḷāta\",\n \"LK-7\": \"Uturumæ̆da paḷāta\",\n \"LK-8\": \"Ūva paḷāta\",\n \"LK-6\": \"Vayamba paḷāta\",\n \"SD-RS\": \"Al Baḩr al Aḩmar\",\n \"SD-GZ\": \"Al Jazīrah\",\n \"SD-KH\": \"Al Kharţūm\",\n \"SD-GD\": \"Al Qaḑārif\",\n \"SD-NW\": \"An Nīl al Abyaḑ\",\n \"SD-NB\": \"An Nīl al Azraq\",\n \"SD-NO\": \"Ash Shamālīyah\",\n \"SD-DW\": \"Gharb Dārfūr\",\n \"SD-GK\": \"Gharb Kurdufān\",\n \"SD-DS\": \"Janūb Dārfūr\",\n \"SD-KS\": \"Janūb Kurdufān\",\n \"SD-KA\": \"Kassalā\",\n \"SD-NR\": \"Nahr an Nīl\",\n \"SD-DN\": \"Shamāl Dārfūr\",\n \"SD-KN\": \"Shamāl Kurdufān\",\n \"SD-DE\": \"Sharq Dārfūr\",\n \"SD-SI\": \"Sinnār\",\n \"SD-DC\": \"Wasaţ Dārfūr\",\n \"SR-BR\": \"Brokopondo\",\n \"SR-CM\": \"Commewijne\",\n \"SR-CR\": \"Coronie\",\n \"SR-MA\": \"Marowijne\",\n \"SR-NI\": \"Nickerie\",\n \"SR-PR\": \"Para\",\n \"SR-PM\": \"Paramaribo\",\n \"SR-SA\": \"Saramacca\",\n \"SR-SI\": \"Sipaliwini\",\n \"SR-WA\": \"Wanica\",\n \"SZ-HH\": \"Hhohho\",\n \"SZ-LU\": \"Lubombo\",\n \"SZ-MA\": \"Manzini\",\n \"SZ-SH\": \"Shiselweni\",\n \"SE-K\": \"Blekinge län\",\n \"SE-W\": \"Dalarnas län\",\n \"SE-I\": \"Gotlands län\",\n \"SE-X\": \"Gävleborgs län\",\n \"SE-N\": \"Hallands län\",\n \"SE-Z\": \"Jämtlands län\",\n \"SE-F\": \"Jönköpings län\",\n \"SE-H\": \"Kalmar län\",\n \"SE-G\": \"Kronobergs län\",\n \"SE-BD\": \"Norrbottens län\",\n \"SE-M\": \"Skåne län\",\n \"SE-AB\": \"Stockholms län\",\n \"SE-D\": \"Södermanlands län\",\n \"SE-C\": \"Uppsala län\",\n \"SE-S\": \"Värmlands län\",\n \"SE-AC\": \"Västerbottens län\",\n \"SE-Y\": \"Västernorrlands län\",\n \"SE-U\": \"Västmanlands län\",\n \"SE-O\": \"Västra Götalands län\",\n \"SE-T\": \"Örebro län\",\n \"SE-E\": \"Östergötlands län\",\n \"CH-AG\": \"Aargau\",\n \"CH-AR\": \"Appenzell Ausserrhoden\",\n \"CH-AI\": \"Appenzell Innerrhoden\",\n \"CH-BL\": \"Basel-Landschaft\",\n \"CH-BS\": \"Basel-Stadt\",\n \"CH-BE\": \"Bern\",\n \"CH-FR\": \"Fribourg\",\n \"CH-GE\": \"Genève\",\n \"CH-GL\": \"Glarus\",\n \"CH-GR\": \"Graubünden\",\n \"CH-JU\": \"Jura\",\n \"CH-LU\": \"Luzern\",\n \"CH-NE\": \"Neuchâtel\",\n \"CH-NW\": \"Nidwalden\",\n \"CH-OW\": \"Obwalden\",\n \"CH-SG\": \"Sankt Gallen\",\n \"CH-SH\": \"Schaffhausen\",\n \"CH-SZ\": \"Schwyz\",\n \"CH-SO\": \"Solothurn\",\n \"CH-TG\": \"Thurgau\",\n \"CH-TI\": \"Ticino\",\n \"CH-UR\": \"Uri\",\n \"CH-VS\": \"Valais\",\n \"CH-VD\": \"Vaud\",\n \"CH-ZG\": \"Zug\",\n \"CH-ZH\": \"Zürich\",\n \"SY-HA\": \"Al Ḩasakah\",\n \"SY-LA\": \"Al Lādhiqīyah\",\n \"SY-QU\": \"Al Qunayţirah\",\n \"SY-RA\": \"Ar Raqqah\",\n \"SY-SU\": \"As Suwaydā'\",\n \"SY-DR\": \"Dar'ā\",\n \"SY-DY\": \"Dayr az Zawr\",\n \"SY-DI\": \"Dimashq\",\n \"SY-HL\": \"Ḩalab\",\n \"SY-HM\": \"Ḩamāh\",\n \"SY-HI\": \"Ḩimş\",\n \"SY-ID\": \"Idlib\",\n \"SY-RD\": \"Rīf Dimashq\",\n \"SY-TA\": \"Ţarţūs\",\n \"TW-CHA\": \"Changhua\",\n \"TW-CYI\": \"Chiayi\",\n \"TW-CYQ\": \"Chiayi\",\n \"TW-HSZ\": \"Hsinchu\",\n \"TW-HSQ\": \"Hsinchu\",\n \"TW-HUA\": \"Hualien\",\n \"TW-KHH\": \"Kaohsiung\",\n \"TW-KEE\": \"Keelung\",\n \"TW-KIN\": \"Kinmen\",\n \"TW-LIE\": \"Lienchiang\",\n \"TW-MIA\": \"Miaoli\",\n \"TW-NAN\": \"Nantou\",\n \"TW-NWT\": \"New Taipei\",\n \"TW-PEN\": \"Penghu\",\n \"TW-PIF\": \"Pingtung\",\n \"TW-TXG\": \"Taichung\",\n \"TW-TNN\": \"Tainan\",\n \"TW-TPE\": \"Taipei\",\n \"TW-TTT\": \"Taitung\",\n \"TW-TAO\": \"Taoyuan\",\n \"TW-ILA\": \"Yilan\",\n \"TW-YUN\": \"Yunlin\",\n \"TJ-DU\": \"Dushanbe\",\n \"TJ-KT\": \"Khatlon\",\n \"TJ-GB\": \"Kŭhistoni Badakhshon\",\n \"TJ-RA\": \"nohiyahoi tobei jumhurí\",\n \"TJ-SU\": \"Sughd\",\n \"TZ-01\": \"Arusha\",\n \"TZ-02\": \"Dar es Salaam\",\n \"TZ-03\": \"Dodoma\",\n \"TZ-27\": \"Geita\",\n \"TZ-04\": \"Iringa\",\n \"TZ-05\": \"Kagera\",\n \"TZ-06\": \"Kaskazini Pemba\",\n \"TZ-07\": \"Kaskazini Unguja\",\n \"TZ-28\": \"Katavi\",\n \"TZ-08\": \"Kigoma\",\n \"TZ-09\": \"Kilimanjaro\",\n \"TZ-10\": \"Kusini Pemba\",\n \"TZ-11\": \"Kusini Unguja\",\n \"TZ-12\": \"Lindi\",\n \"TZ-26\": \"Manyara\",\n \"TZ-13\": \"Mara\",\n \"TZ-14\": \"Mbeya\",\n \"TZ-15\": \"Mjini Magharibi\",\n \"TZ-16\": \"Morogoro\",\n \"TZ-17\": \"Mtwara\",\n \"TZ-18\": \"Mwanza\",\n \"TZ-29\": \"Njombe\",\n \"TZ-19\": \"Pwani\",\n \"TZ-20\": \"Rukwa\",\n \"TZ-21\": \"Ruvuma\",\n \"TZ-22\": \"Shinyanga\",\n \"TZ-30\": \"Simiyu\",\n \"TZ-23\": \"Singida\",\n \"TZ-31\": \"Songwe\",\n \"TZ-24\": \"Tabora\",\n \"TZ-25\": \"Tanga\",\n \"TH-37\": \"Amnat Charoen\",\n \"TH-15\": \"Ang Thong\",\n \"TH-38\": \"Bueng Kan\",\n \"TH-31\": \"Buri Ram\",\n \"TH-24\": \"Chachoengsao\",\n \"TH-18\": \"Chai Nat\",\n \"TH-36\": \"Chaiyaphum\",\n \"TH-22\": \"Chanthaburi\",\n \"TH-50\": \"Chiang Mai\",\n \"TH-57\": \"Chiang Rai\",\n \"TH-20\": \"Chon Buri\",\n \"TH-86\": \"Chumphon\",\n \"TH-46\": \"Kalasin\",\n \"TH-62\": \"Kamphaeng Phet\",\n \"TH-71\": \"Kanchanaburi\",\n \"TH-40\": \"Khon Kaen\",\n \"TH-81\": \"Krabi\",\n \"TH-10\": \"Bangkok\",\n \"TH-52\": \"Lampang\",\n \"TH-51\": \"Lamphun\",\n \"TH-42\": \"Loei\",\n \"TH-16\": \"Lop Buri\",\n \"TH-58\": \"Mae Hong Son\",\n \"TH-44\": \"Maha Sarakham\",\n \"TH-49\": \"Mukdahan\",\n \"TH-26\": \"Nakhon Nayok\",\n \"TH-73\": \"Nakhon Pathom\",\n \"TH-48\": \"Nakhon Phanom\",\n \"TH-30\": \"Nakhon Ratchasima\",\n \"TH-60\": \"Nakhon Sawan\",\n \"TH-80\": \"Nakhon Si Thammarat\",\n \"TH-55\": \"Nan\",\n \"TH-96\": \"Narathiwat\",\n \"TH-39\": \"Nong Bua Lam Phu\",\n \"TH-43\": \"Nong Khai\",\n \"TH-12\": \"Nonthaburi\",\n \"TH-13\": \"Pathum Thani\",\n \"TH-94\": \"Pattani\",\n \"TH-82\": \"Phangnga\",\n \"TH-93\": \"Phatthalung\",\n \"TH-S\": \"Phatthaya\",\n \"TH-56\": \"Phayao\",\n \"TH-67\": \"Phetchabun\",\n \"TH-76\": \"Phetchaburi\",\n \"TH-66\": \"Phichit\",\n \"TH-65\": \"Phitsanulok\",\n \"TH-14\": \"Phra Nakhon Si Ayutthaya\",\n \"TH-54\": \"Phrae\",\n \"TH-83\": \"Phuket\",\n \"TH-25\": \"Prachin Buri\",\n \"TH-77\": \"Prachuap Khiri Khan\",\n \"TH-85\": \"Ranong\",\n \"TH-70\": \"Ratchaburi\",\n \"TH-21\": \"Rayong\",\n \"TH-45\": \"Roi Et\",\n \"TH-27\": \"Sa Kaeo\",\n \"TH-47\": \"Sakon Nakhon\",\n \"TH-11\": \"Samut Prakan\",\n \"TH-74\": \"Samut Sakhon\",\n \"TH-75\": \"Samut Songkhram\",\n \"TH-19\": \"Saraburi\",\n \"TH-91\": \"Satun\",\n \"TH-33\": \"Si Sa Ket\",\n \"TH-17\": \"Sing Buri\",\n \"TH-90\": \"Songkhla\",\n \"TH-64\": \"Sukhothai\",\n \"TH-72\": \"Suphan Buri\",\n \"TH-84\": \"Surat Thani\",\n \"TH-32\": \"Surin\",\n \"TH-63\": \"Tak\",\n \"TH-92\": \"Trang\",\n \"TH-23\": \"Trat\",\n \"TH-34\": \"Ubon Ratchathani\",\n \"TH-41\": \"Udon Thani\",\n \"TH-61\": \"Uthai Thani\",\n \"TH-53\": \"Uttaradit\",\n \"TH-95\": \"Yala\",\n \"TH-35\": \"Yasothon\",\n \"TL-AL\": \"Aileu\",\n \"TL-AN\": \"Ainaro\",\n \"TL-BA\": \"Baucau\",\n \"TL-BO\": \"Bobonaro\",\n \"TL-CO\": \"Cova Lima\",\n \"TL-DI\": \"Díli\",\n \"TL-ER\": \"Ermera\",\n \"TL-LA\": \"Lautém\",\n \"TL-LI\": \"Liquiça\",\n \"TL-MT\": \"Manatuto\",\n \"TL-MF\": \"Manufahi\",\n \"TL-OE\": \"Oé-Cusse Ambeno\",\n \"TL-VI\": \"Viqueque\",\n \"TG-C\": \"Centrale\",\n \"TG-K\": \"Kara\",\n \"TG-M\": \"Maritime\",\n \"TG-P\": \"Plateaux\",\n \"TG-S\": \"Savanes\",\n \"TO-01\": \"'Eua\",\n \"TO-02\": \"Ha'apai\",\n \"TO-03\": \"Niuas\",\n \"TO-04\": \"Tongatapu\",\n \"TO-05\": \"Vava'u\",\n \"TT-ARI\": \"Arima\",\n \"TT-CHA\": \"Chaguanas\",\n \"TT-CTT\": \"Couva-Tabaquite-Talparo\",\n \"TT-DMN\": \"Diego Martin\",\n \"TT-MRC\": \"Mayaro-Rio Claro\",\n \"TT-PED\": \"Penal-Debe\",\n \"TT-POS\": \"Port of Spain\",\n \"TT-PRT\": \"Princes Town\",\n \"TT-PTF\": \"Point Fortin\",\n \"TT-SFO\": \"San Fernando\",\n \"TT-SGE\": \"Sangre Grande\",\n \"TT-SIP\": \"Siparia\",\n \"TT-SJL\": \"San Juan-Laventille\",\n \"TT-TOB\": \"Tobago\",\n \"TT-TUP\": \"Tunapuna-Piarco\",\n \"TN-31\": \"Béja\",\n \"TN-13\": \"Ben Arous\",\n \"TN-23\": \"Bizerte\",\n \"TN-81\": \"Gabès\",\n \"TN-71\": \"Gafsa\",\n \"TN-32\": \"Jendouba\",\n \"TN-41\": \"Kairouan\",\n \"TN-42\": \"Kasserine\",\n \"TN-73\": \"Kébili\",\n \"TN-12\": \"L'Ariana\",\n \"TN-14\": \"La Manouba\",\n \"TN-33\": \"Le Kef\",\n \"TN-53\": \"Mahdia\",\n \"TN-82\": \"Médenine\",\n \"TN-52\": \"Monastir\",\n \"TN-21\": \"Nabeul\",\n \"TN-61\": \"Sfax\",\n \"TN-43\": \"Sidi Bouzid\",\n \"TN-34\": \"Siliana\",\n \"TN-51\": \"Sousse\",\n \"TN-83\": \"Tataouine\",\n \"TN-72\": \"Tozeur\",\n \"TN-11\": \"Tunis\",\n \"TN-22\": \"Zaghouan\",\n \"TR-01\": \"Adana\",\n \"TR-02\": \"Adıyaman\",\n \"TR-03\": \"Afyonkarahisar\",\n \"TR-04\": \"Ağrı\",\n \"TR-68\": \"Aksaray\",\n \"TR-05\": \"Amasya\",\n \"TR-06\": \"Ankara\",\n \"TR-07\": \"Antalya\",\n \"TR-75\": \"Ardahan\",\n \"TR-08\": \"Artvin\",\n \"TR-09\": \"Aydın\",\n \"TR-10\": \"Balıkesir\",\n \"TR-74\": \"Bartın\",\n \"TR-72\": \"Batman\",\n \"TR-69\": \"Bayburt\",\n \"TR-11\": \"Bilecik\",\n \"TR-12\": \"Bingöl\",\n \"TR-13\": \"Bitlis\",\n \"TR-14\": \"Bolu\",\n \"TR-15\": \"Burdur\",\n \"TR-16\": \"Bursa\",\n \"TR-17\": \"Çanakkale\",\n \"TR-18\": \"Çankırı\",\n \"TR-19\": \"Çorum\",\n \"TR-20\": \"Denizli\",\n \"TR-21\": \"Diyarbakır\",\n \"TR-81\": \"Düzce\",\n \"TR-22\": \"Edirne\",\n \"TR-23\": \"Elazığ\",\n \"TR-24\": \"Erzincan\",\n \"TR-25\": \"Erzurum\",\n \"TR-26\": \"Eskişehir\",\n \"TR-27\": \"Gaziantep\",\n \"TR-28\": \"Giresun\",\n \"TR-29\": \"Gümüşhane\",\n \"TR-30\": \"Hakkâri\",\n \"TR-31\": \"Hatay\",\n \"TR-76\": \"Iğdır\",\n \"TR-32\": \"Isparta\",\n \"TR-34\": \"İstanbul\",\n \"TR-35\": \"İzmir\",\n \"TR-46\": \"Kahramanmaraş\",\n \"TR-78\": \"Karabük\",\n \"TR-70\": \"Karaman\",\n \"TR-36\": \"Kars\",\n \"TR-37\": \"Kastamonu\",\n \"TR-38\": \"Kayseri\",\n \"TR-71\": \"Kırıkkale\",\n \"TR-39\": \"Kırklareli\",\n \"TR-40\": \"Kırşehir\",\n \"TR-79\": \"Kilis\",\n \"TR-41\": \"Kocaeli\",\n \"TR-42\": \"Konya\",\n \"TR-43\": \"Kütahya\",\n \"TR-44\": \"Malatya\",\n \"TR-45\": \"Manisa\",\n \"TR-47\": \"Mardin\",\n \"TR-33\": \"Mersin\",\n \"TR-48\": \"Muğla\",\n \"TR-49\": \"Muş\",\n \"TR-50\": \"Nevşehir\",\n \"TR-51\": \"Niğde\",\n \"TR-52\": \"Ordu\",\n \"TR-80\": \"Osmaniye\",\n \"TR-53\": \"Rize\",\n \"TR-54\": \"Sakarya\",\n \"TR-55\": \"Samsun\",\n \"TR-56\": \"Siirt\",\n \"TR-57\": \"Sinop\",\n \"TR-58\": \"Sivas\",\n \"TR-63\": \"Şanlıurfa\",\n \"TR-73\": \"Şırnak\",\n \"TR-59\": \"Tekirdağ\",\n \"TR-60\": \"Tokat\",\n \"TR-61\": \"Trabzon\",\n \"TR-62\": \"Tunceli\",\n \"TR-64\": \"Uşak\",\n \"TR-65\": \"Van\",\n \"TR-77\": \"Yalova\",\n \"TR-66\": \"Yozgat\",\n \"TR-67\": \"Zonguldak\",\n \"TM-A\": \"Ahal\",\n \"TM-S\": \"Aşgabat\",\n \"TM-B\": \"Balkan\",\n \"TM-D\": \"Daşoguz\",\n \"TM-L\": \"Lebap\",\n \"TM-M\": \"Mary\",\n \"TV-FUN\": \"Funafuti\",\n \"TV-NMG\": \"Nanumaga\",\n \"TV-NMA\": \"Nanumea\",\n \"TV-NIT\": \"Niutao\",\n \"TV-NUI\": \"Nui\",\n \"TV-NKF\": \"Nukufetau\",\n \"TV-NKL\": \"Nukulaelae\",\n \"TV-VAI\": \"Vaitupu\",\n \"UG-C\": \"Central\",\n \"UG-E\": \"Eastern\",\n \"UG-N\": \"Northern\",\n \"UG-W\": \"Western\",\n \"UA-43\": \"Avtonomna Respublika Krym\",\n \"UA-71\": \"Cherkaska oblast\",\n \"UA-74\": \"Chernihivska oblast\",\n \"UA-77\": \"Chernivetska oblast\",\n \"UA-12\": \"Dnipropetrovska oblast\",\n \"UA-14\": \"Donetska oblast\",\n \"UA-26\": \"Ivano-Frankivska oblast\",\n \"UA-63\": \"Kharkivska oblast\",\n \"UA-65\": \"Khersonska oblast\",\n \"UA-68\": \"Khmelnytska oblast\",\n \"UA-35\": \"Kirovohradska oblast\",\n \"UA-30\": \"Kyiv\",\n \"UA-32\": \"Kyivska oblast\",\n \"UA-09\": \"Luhanska oblast\",\n \"UA-46\": \"Lvivska oblast\",\n \"UA-48\": \"Mykolaivska oblast\",\n \"UA-51\": \"Odeska oblast\",\n \"UA-53\": \"Poltavska oblast\",\n \"UA-56\": \"Rivnenska oblast\",\n \"UA-40\": \"Sevastopol\",\n \"UA-59\": \"Sumska oblast\",\n \"UA-61\": \"Ternopilska oblast\",\n \"UA-05\": \"Vinnytska oblast\",\n \"UA-07\": \"Volynska oblast\",\n \"UA-21\": \"Zakarpatska oblast\",\n \"UA-23\": \"Zaporizka oblast\",\n \"UA-18\": \"Zhytomyrska oblast\",\n \"AE-AJ\": \"‘Ajmān\",\n \"AE-AZ\": \"Abū Z̧aby\",\n \"AE-FU\": \"Al Fujayrah\",\n \"AE-SH\": \"Ash Shāriqah\",\n \"AE-DU\": \"Dubayy\",\n \"AE-RK\": \"Ra’s al Khaymah\",\n \"AE-UQ\": \"Umm al Qaywayn\",\n \"GB-ENG\": \"England\",\n \"GB-NIR\": \"Northern Ireland\",\n \"GB-SCT\": \"Scotland\",\n \"GB-WLS\": \"Wales\",\n \"US-AL\": \"Alabama\",\n \"US-AK\": \"Alaska\",\n \"US-AZ\": \"Arizona\",\n \"US-AR\": \"Arkansas\",\n \"US-CA\": \"California\",\n \"US-CO\": \"Colorado\",\n \"US-CT\": \"Connecticut\",\n \"US-DE\": \"Delaware\",\n \"US-FL\": \"Florida\",\n \"US-GA\": \"Georgia\",\n \"US-HI\": \"Hawaii\",\n \"US-ID\": \"Idaho\",\n \"US-IL\": \"Illinois\",\n \"US-IN\": \"Indiana\",\n \"US-IA\": \"Iowa\",\n \"US-KS\": \"Kansas\",\n \"US-KY\": \"Kentucky\",\n \"US-LA\": \"Louisiana\",\n \"US-ME\": \"Maine\",\n \"US-MD\": \"Maryland\",\n \"US-MA\": \"Massachusetts\",\n \"US-MI\": \"Michigan\",\n \"US-MN\": \"Minnesota\",\n \"US-MS\": \"Mississippi\",\n \"US-MO\": \"Missouri\",\n \"US-MT\": \"Montana\",\n \"US-NE\": \"Nebraska\",\n \"US-NV\": \"Nevada\",\n \"US-NH\": \"New Hampshire\",\n \"US-NJ\": \"New Jersey\",\n \"US-NM\": \"New Mexico\",\n \"US-NY\": \"New York\",\n \"US-NC\": \"North Carolina\",\n \"US-ND\": \"North Dakota\",\n \"US-OH\": \"Ohio\",\n \"US-OK\": \"Oklahoma\",\n \"US-OR\": \"Oregon\",\n \"US-PA\": \"Pennsylvania\",\n \"US-RI\": \"Rhode Island\",\n \"US-SC\": \"South Carolina\",\n \"US-SD\": \"South Dakota\",\n \"US-TN\": \"Tennessee\",\n \"US-TX\": \"Texas\",\n \"US-UT\": \"Utah\",\n \"US-VT\": \"Vermont\",\n \"US-VA\": \"Virginia\",\n \"US-WA\": \"Washington\",\n \"US-WV\": \"West Virginia\",\n \"US-WI\": \"Wisconsin\",\n \"US-WY\": \"Wyoming\",\n \"US-DC\": \"District of Columbia\",\n \"US-AS\": \"American Samoa\",\n \"US-GU\": \"Guam\",\n \"US-MP\": \"Northern Mariana Islands\",\n \"US-PR\": \"Puerto Rico\",\n \"US-UM\": \"United States Minor Outlying Islands\",\n \"US-VI\": \"Virgin Islands\",\n \"UM-81\": \"Baker Island\",\n \"UM-84\": \"Howland Island\",\n \"UM-86\": \"Jarvis Island\",\n \"UM-67\": \"Johnston Atoll\",\n \"UM-89\": \"Kingman Reef\",\n \"UM-71\": \"Midway Islands\",\n \"UM-76\": \"Navassa Island\",\n \"UM-95\": \"Palmyra Atoll\",\n \"UM-79\": \"Wake Island\",\n \"UY-AR\": \"Artigas\",\n \"UY-CA\": \"Canelones\",\n \"UY-CL\": \"Cerro Largo\",\n \"UY-CO\": \"Colonia\",\n \"UY-DU\": \"Durazno\",\n \"UY-FS\": \"Flores\",\n \"UY-FD\": \"Florida\",\n \"UY-LA\": \"Lavalleja\",\n \"UY-MA\": \"Maldonado\",\n \"UY-MO\": \"Montevideo\",\n \"UY-PA\": \"Paysandú\",\n \"UY-RN\": \"Río Negro\",\n \"UY-RV\": \"Rivera\",\n \"UY-RO\": \"Rocha\",\n \"UY-SA\": \"Salto\",\n \"UY-SJ\": \"San José\",\n \"UY-SO\": \"Soriano\",\n \"UY-TA\": \"Tacuarembó\",\n \"UY-TT\": \"Treinta y Tres\",\n \"UZ-AN\": \"Andijon\",\n \"UZ-BU\": \"Buxoro\",\n \"UZ-FA\": \"Farg‘ona\",\n \"UZ-JI\": \"Jizzax\",\n \"UZ-NG\": \"Namangan\",\n \"UZ-NW\": \"Navoiy\",\n \"UZ-QA\": \"Qashqadaryo\",\n \"UZ-QR\": \"Qoraqalpog‘iston Respublikasi\",\n \"UZ-SA\": \"Samarqand\",\n \"UZ-SI\": \"Sirdaryo\",\n \"UZ-SU\": \"Surxondaryo\",\n \"UZ-TK\": \"Toshkent\",\n \"UZ-TO\": \"Toshkent\",\n \"UZ-XO\": \"Xorazm\",\n \"VU-MAP\": \"Malampa\",\n \"VU-PAM\": \"Pénama\",\n \"VU-SAM\": \"Sanma\",\n \"VU-SEE\": \"Shéfa\",\n \"VU-TAE\": \"Taféa\",\n \"VU-TOB\": \"Torba\",\n \"VE-Z\": \"Amazonas\",\n \"VE-B\": \"Anzoátegui\",\n \"VE-C\": \"Apure\",\n \"VE-D\": \"Aragua\",\n \"VE-E\": \"Barinas\",\n \"VE-F\": \"Bolívar\",\n \"VE-G\": \"Carabobo\",\n \"VE-H\": \"Cojedes\",\n \"VE-Y\": \"Delta Amacuro\",\n \"VE-W\": \"Dependencias Federales\",\n \"VE-A\": \"Distrito Capital\",\n \"VE-I\": \"Falcón\",\n \"VE-J\": \"Guárico\",\n \"VE-X\": \"La Guaira\",\n \"VE-K\": \"Lara\",\n \"VE-L\": \"Mérida\",\n \"VE-M\": \"Miranda\",\n \"VE-N\": \"Monagas\",\n \"VE-O\": \"Nueva Esparta\",\n \"VE-P\": \"Portuguesa\",\n \"VE-R\": \"Sucre\",\n \"VE-S\": \"Táchira\",\n \"VE-T\": \"Trujillo\",\n \"VE-U\": \"Yaracuy\",\n \"VE-V\": \"Zulia\",\n \"VN-44\": \"An Giang\",\n \"VN-43\": \"Bà Rịa - Vũng Tàu\",\n \"VN-54\": \"Bắc Giang\",\n \"VN-53\": \"Bắc Kạn\",\n \"VN-55\": \"Bạc Liêu\",\n \"VN-56\": \"Bắc Ninh\",\n \"VN-50\": \"Bến Tre\",\n \"VN-31\": \"Bình Định\",\n \"VN-57\": \"Bình Dương\",\n \"VN-58\": \"Bình Phước\",\n \"VN-40\": \"Bình Thuận\",\n \"VN-59\": \"Cà Mau\",\n \"VN-CT\": \"Cần Thơ\",\n \"VN-04\": \"Cao Bằng\",\n \"VN-DN\": \"Đà Nẵng\",\n \"VN-33\": \"Đắk Lắk\",\n \"VN-72\": \"Đắk Nông\",\n \"VN-71\": \"Điện Biên\",\n \"VN-39\": \"Đồng Nai\",\n \"VN-45\": \"Đồng Tháp\",\n \"VN-30\": \"Gia Lai\",\n \"VN-03\": \"Hà Giang\",\n \"VN-63\": \"Hà Nam\",\n \"VN-HN\": \"Hà Nội\",\n \"VN-23\": \"Hà Tĩnh\",\n \"VN-61\": \"Hải Dương\",\n \"VN-HP\": \"Hải Phòng\",\n \"VN-73\": \"Hậu Giang\",\n \"VN-SG\": \"Hồ Chí Minh\",\n \"VN-14\": \"Hòa Bình\",\n \"VN-66\": \"Hưng Yên\",\n \"VN-34\": \"Khánh Hòa\",\n \"VN-47\": \"Kiến Giang\",\n \"VN-28\": \"Kon Tum\",\n \"VN-01\": \"Lai Châu\",\n \"VN-35\": \"Lâm Đồng\",\n \"VN-09\": \"Lạng Sơn\",\n \"VN-02\": \"Lào Cai\",\n \"VN-41\": \"Long An\",\n \"VN-67\": \"Nam Định\",\n \"VN-22\": \"Nghệ An\",\n \"VN-18\": \"Ninh Bình\",\n \"VN-36\": \"Ninh Thuận\",\n \"VN-68\": \"Phú Thọ\",\n \"VN-32\": \"Phú Yên\",\n \"VN-24\": \"Quảng Bình\",\n \"VN-27\": \"Quảng Nam\",\n \"VN-29\": \"Quảng Ngãi\",\n \"VN-13\": \"Quảng Ninh\",\n \"VN-25\": \"Quảng Trị\",\n \"VN-52\": \"Sóc Trăng\",\n \"VN-05\": \"Sơn La\",\n \"VN-37\": \"Tây Ninh\",\n \"VN-20\": \"Thái Bình\",\n \"VN-69\": \"Thái Nguyên\",\n \"VN-21\": \"Thanh Hóa\",\n \"VN-26\": \"Thừa Thiên-Huế\",\n \"VN-46\": \"Tiền Giang\",\n \"VN-51\": \"Trà Vinh\",\n \"VN-07\": \"Tuyên Quang\",\n \"VN-49\": \"Vĩnh Long\",\n \"VN-70\": \"Vĩnh Phúc\",\n \"VN-06\": \"Yên Bái\",\n \"WF-AL\": \"Alo\",\n \"WF-SG\": \"Sigave\",\n \"WF-UV\": \"Uvea\",\n \"YE-AD\": \"‘Adan\",\n \"YE-AM\": \"‘Amrān\",\n \"YE-AB\": \"Abyan\",\n \"YE-DA\": \"Aḑ Ḑāli‘\",\n \"YE-BA\": \"Al Bayḑā’\",\n \"YE-HU\": \"Al Ḩudaydah\",\n \"YE-JA\": \"Al Jawf\",\n \"YE-MR\": \"Al Mahrah\",\n \"YE-MW\": \"Al Maḩwīt\",\n \"YE-SA\": \"Amānat al ‘Āşimah\",\n \"YE-SU\": \"Arkhabīl Suquţrá\",\n \"YE-DH\": \"Dhamār\",\n \"YE-HD\": \"Ḩaḑramawt\",\n \"YE-HJ\": \"Ḩajjah\",\n \"YE-IB\": \"Ibb\",\n \"YE-LA\": \"Laḩij\",\n \"YE-MA\": \"Ma’rib\",\n \"YE-RA\": \"Raymah\",\n \"YE-SD\": \"Şāʻdah\",\n \"YE-SN\": \"Şanʻā’\",\n \"YE-SH\": \"Shabwah\",\n \"YE-TA\": \"Tāʻizz\",\n \"ZM-02\": \"Central\",\n \"ZM-08\": \"Copperbelt\",\n \"ZM-03\": \"Eastern\",\n \"ZM-04\": \"Luapula\",\n \"ZM-09\": \"Lusaka\",\n \"ZM-10\": \"Muchinga\",\n \"ZM-06\": \"North-Western\",\n \"ZM-05\": \"Northern\",\n \"ZM-07\": \"Southern\",\n \"ZM-01\": \"Western\",\n \"ZW-BU\": \"Bulawayo\",\n \"ZW-HA\": \"Harare\",\n \"ZW-MA\": \"Manicaland\",\n \"ZW-MC\": \"Mashonaland Central\",\n \"ZW-ME\": \"Mashonaland East\",\n \"ZW-MW\": \"Mashonaland West\",\n \"ZW-MV\": \"Masvingo\",\n \"ZW-MN\": \"Matabeleland North\",\n \"ZW-MS\": \"Matabeleland South\",\n \"ZW-MI\": \"Midlands\",\n \"BQ-BO\": \"Bonaire\",\n \"BQ-SA\": \"Saba\",\n \"BQ-SE\": \"Sint Eustatius\",\n \"ME-01\": \"Andrijevica\",\n \"ME-02\": \"Bar\",\n \"ME-03\": \"Berane\",\n \"ME-04\": \"Bijelo Polje\",\n \"ME-05\": \"Budva\",\n \"ME-06\": \"Cetinje\",\n \"ME-07\": \"Danilovgrad\",\n \"ME-22\": \"Gusinje\",\n \"ME-08\": \"Herceg-Novi\",\n \"ME-09\": \"Kolašin\",\n \"ME-10\": \"Kotor\",\n \"ME-11\": \"Mojkovac\",\n \"ME-12\": \"Nikšić\",\n \"ME-23\": \"Petnjica\",\n \"ME-13\": \"Plav\",\n \"ME-14\": \"Pljevlja\",\n \"ME-15\": \"Plužine\",\n \"ME-16\": \"Podgorica\",\n \"ME-17\": \"Rožaje\",\n \"ME-18\": \"Šavnik\",\n \"ME-19\": \"Tivat\",\n \"ME-24\": \"Tuzi\",\n \"ME-20\": \"Ulcinj\",\n \"ME-21\": \"Žabljak\",\n \"ME-25\": \"Zeta\",\n \"RS-KM\": \"Kosovo-Metohija\",\n \"RS-VO\": \"Vojvodina\",\n \"SS-EC\": \"Central Equatoria\",\n \"SS-EE\": \"Eastern Equatoria\",\n \"SS-JG\": \"Jonglei\",\n \"SS-LK\": \"Lakes\",\n \"SS-BN\": \"Northern Bahr el Ghazal\",\n \"SS-UY\": \"Unity\",\n \"SS-NU\": \"Upper Nile\",\n \"SS-WR\": \"Warrap\",\n \"SS-BW\": \"Western Bahr el Ghazal\",\n \"SS-EW\": \"Western Equatoria\",\n};\n\nexport const REGION_CODES = Object.keys(REGIONS) as [string, ...string[]];\n","/**\n * Country Code Top-Level Domains (ccTLDs)\n * Provides a comprehensive set of all country-specific domain extensions\n */\n\n/**\n * A Set containing ISO 3166-1 alpha-2 country code top-level domains (ccTLDs),\n * plus a small set of commonly-recognized regional TLDs (`eu`, `eus`, `gal`,\n * `cat`, `asia`). De-duplicated and pruned of retired/withdrawn codes:\n * - `an` (Netherlands Antilles, retired 2010)\n * - `tp` (Timor-Leste, retired 2015 — use `tl`)\n * `gb` is included alongside `uk` per IANA reservation.\n *\n * @example\n * ```ts\n * import { ccTLDs } from '@kumix/utils';\n *\n * // Check if a TLD is a country code TLD\n * const isCountryTLD = ccTLDs.has('uk'); // true\n *\n * // Extract TLD from domain and check\n * const domain = 'example.co.uk';\n * const tld = domain.split('.').pop();\n * const isCountryDomain = tld ? ccTLDs.has(tld) : false; // true\n * ```\n */\nexport const ccTLDs = new Set([\n \"ac\",\n \"ad\",\n \"ae\",\n \"af\",\n \"ag\",\n \"ai\",\n \"al\",\n \"am\",\n \"ao\",\n \"aq\",\n \"ar\",\n \"as\",\n \"at\",\n \"au\",\n \"aw\",\n \"ax\",\n \"az\",\n \"ba\",\n \"bb\",\n \"bd\",\n \"be\",\n \"bf\",\n \"bg\",\n \"bh\",\n \"bi\",\n \"bj\",\n \"bl\",\n \"bm\",\n \"bn\",\n \"bo\",\n \"bq\",\n \"br\",\n \"bs\",\n \"bt\",\n \"bv\",\n \"bw\",\n \"by\",\n \"bz\",\n \"ca\",\n \"cat\",\n \"cc\",\n \"cd\",\n \"cf\",\n \"cg\",\n \"ch\",\n \"ci\",\n \"ck\",\n \"cl\",\n \"cm\",\n \"cn\",\n \"co\",\n \"cr\",\n \"cu\",\n \"cv\",\n \"cw\",\n \"cx\",\n \"cy\",\n \"cz\",\n \"de\",\n \"dj\",\n \"dk\",\n \"dm\",\n \"do\",\n \"dz\",\n \"ec\",\n \"ee\",\n \"eg\",\n \"eh\",\n \"er\",\n \"es\",\n \"et\",\n \"eu\",\n \"eus\",\n \"fi\",\n \"fj\",\n \"fk\",\n \"fm\",\n \"fo\",\n \"fr\",\n \"ga\",\n \"gal\",\n \"gb\",\n \"gd\",\n \"ge\",\n \"gf\",\n \"gg\",\n \"gh\",\n \"gi\",\n \"gl\",\n \"gm\",\n \"gn\",\n \"gp\",\n \"gq\",\n \"gr\",\n \"gs\",\n \"gt\",\n \"gu\",\n \"gw\",\n \"gy\",\n \"hk\",\n \"hm\",\n \"hn\",\n \"hr\",\n \"ht\",\n \"hu\",\n \"id\",\n \"ie\",\n \"il\",\n \"im\",\n \"in\",\n \"io\",\n \"iq\",\n \"ir\",\n \"is\",\n \"it\",\n \"je\",\n \"jm\",\n \"jo\",\n \"jp\",\n \"ke\",\n \"kg\",\n \"kh\",\n \"ki\",\n \"km\",\n \"kn\",\n \"kp\",\n \"kr\",\n \"kw\",\n \"ky\",\n \"kz\",\n \"la\",\n \"lb\",\n \"lc\",\n \"li\",\n \"lk\",\n \"lr\",\n \"ls\",\n \"lt\",\n \"lu\",\n \"lv\",\n \"ly\",\n \"ma\",\n \"mc\",\n \"md\",\n \"me\",\n \"mf\",\n \"mg\",\n \"mh\",\n \"mk\",\n \"ml\",\n \"mm\",\n \"mn\",\n \"mo\",\n \"mp\",\n \"mq\",\n \"mr\",\n \"ms\",\n \"mt\",\n \"mu\",\n \"mv\",\n \"mw\",\n \"mx\",\n \"my\",\n \"mz\",\n \"na\",\n \"nc\",\n \"ne\",\n \"nf\",\n \"ng\",\n \"ni\",\n \"nl\",\n \"no\",\n \"np\",\n \"nr\",\n \"nu\",\n \"nz\",\n \"om\",\n \"pa\",\n \"pe\",\n \"pf\",\n \"pg\",\n \"ph\",\n \"pk\",\n \"pl\",\n \"pm\",\n \"pn\",\n \"pr\",\n \"ps\",\n \"pt\",\n \"pw\",\n \"py\",\n \"qa\",\n \"re\",\n \"ro\",\n \"rs\",\n \"ru\",\n \"rw\",\n \"sa\",\n \"sb\",\n \"sc\",\n \"sd\",\n \"se\",\n \"sg\",\n \"sh\",\n \"si\",\n \"sj\",\n \"sk\",\n \"sl\",\n \"sm\",\n \"sn\",\n \"so\",\n \"sr\",\n \"ss\",\n \"st\",\n \"sv\",\n \"sx\",\n \"sy\",\n \"sz\",\n \"tc\",\n \"td\",\n \"tf\",\n \"tg\",\n \"th\",\n \"tj\",\n \"tk\",\n \"tl\",\n \"tm\",\n \"tn\",\n \"to\",\n \"tr\",\n \"tt\",\n \"tv\",\n \"tw\",\n \"tz\",\n \"ua\",\n \"ug\",\n \"uk\",\n \"um\",\n \"us\",\n \"uy\",\n \"uz\",\n \"va\",\n \"vc\",\n \"ve\",\n \"vg\",\n \"vi\",\n \"vn\",\n \"vu\",\n \"wf\",\n \"ws\",\n \"ye\",\n \"za\",\n \"zm\",\n \"zw\",\n]);\n","/**\n * Domain Constants\n * Provides sets of domain-related constants for URL parsing and validation\n */\n\n/**\n * Common second-level domains used in domain name structures\n * Used for domain parsing, validation, and extraction of root domains\n *\n * @example\n * ```ts\n * import { SECOND_LEVEL_DOMAINS } from '@kumix/utils';\n *\n * // Check if a domain part is a common second-level domain\n * const isSecondLevelDomain = SECOND_LEVEL_DOMAINS.has('co'); // true\n *\n * // Extract root domain from a URL\n * function getRootDomain(url: string) {\n * const hostname = new URL(url).hostname;\n * const parts = hostname.split('.');\n *\n * // Handle cases like example.co.uk\n * if (parts.length > 2 && SECOND_LEVEL_DOMAINS.has(parts[parts.length - 2])) {\n * return parts.slice(-3).join('.');\n * }\n *\n * // Handle normal cases like example.com\n * return parts.slice(-2).join('.');\n * }\n * ```\n */\nexport const SECOND_LEVEL_DOMAINS = new Set([\"com\", \"co\", \"net\", \"org\", \"edu\", \"gov\", \"in\"]);\n","/**\n * Domain Constants\n * Provides sets of domain-related constants for URL parsing and validation\n */\n\n/**\n * Special apex domains that require special handling\n * These domains are typically used for hosting services where users get subdomains\n *\n * @example\n * ```ts\n * import { SPECIAL_APEX_DOMAINS } from '@kumix/utils';\n *\n * // Check if a domain is a special hosting domain\n * const isSpecialDomain = SPECIAL_APEX_DOMAINS.has('vercel.app'); // true\n *\n * // Determine if a hostname is a user subdomain on a special apex domain\n * function isUserSubdomain(hostname: string) {\n * const parts = hostname.split('.');\n * if (parts.length < 2) return false;\n *\n * const possibleApexDomain = parts.slice(-2).join('.');\n * return SPECIAL_APEX_DOMAINS.has(possibleApexDomain);\n * }\n *\n * // Extract username from special domains\n * function extractUsername(hostname: string) {\n * const parts = hostname.split('.');\n * const possibleApexDomain = parts.slice(-2).join('.');\n *\n * if (SPECIAL_APEX_DOMAINS.has(possibleApexDomain)) {\n * return parts.slice(0, -2).join('.');\n * }\n * return null;\n * }\n * ```\n */\nexport const SPECIAL_APEX_DOMAINS = new Set([\n \"my.id\",\n \"github.io\",\n \"vercel.app\",\n \"now.sh\",\n \"pages.dev\",\n \"webflow.io\",\n \"netlify.app\",\n \"fly.dev\",\n \"web.app\",\n]);\n","/**\n * Theme configuration for the application\n * Handles light, dark, and system theme modes with their respective colors\n */\n\n/**\n * Available theme modes in the application\n * - light: Force light theme\n * - dark: Force dark theme\n * - system: Follow system/OS preference (auto-detect)\n */\nexport const THEME_MODES = {\n LIGHT: \"light\",\n DARK: \"dark\",\n SYSTEM: \"system\",\n} as const;\n\n/**\n * Type definition for theme modes\n */\nexport type ThemeMode = (typeof THEME_MODES)[keyof typeof THEME_MODES];\n\n/**\n * Meta theme colors for different theme modes\n * Used for:\n * - HTML meta theme-color tags\n * - Browser address bar coloring\n * - PWA theme colors\n * - System theme integration\n */\nexport const META_THEME_COLORS = {\n /** Light theme color - Pure white for clean, bright appearance */\n [THEME_MODES.LIGHT]: \"#ffffff\",\n /** Dark theme color - Near black with slight warmth to reduce eye strain */\n [THEME_MODES.DARK]: \"#09090b\",\n /** System theme - Will be determined by user's OS preference */\n [THEME_MODES.SYSTEM]: \"auto\", // Special value indicating system preference\n} as const;\n\n/**\n * Default theme mode when no preference is set\n * Falls back to system preference to respect user's OS settings\n */\nexport const DEFAULT_THEME_MODE: ThemeMode = THEME_MODES.SYSTEM;\n","/**\n * Environment variables used throughout the application\n * Centralizes all environment variable access for easier management and documentation.\n */\n\nimport { getEnv } from \"../env\";\n\n/**\n * Recaptcha site key for client-side verification.\n * Used for Google reCAPTCHA integration in forms and authentication.\n *\n * @example\n * <Recaptcha siteKey={NEXT_PUBLIC_RECAPTCHA_SITE_KEY} />\n */\nexport const NEXT_PUBLIC_RECAPTCHA_SITE_KEY = getEnv(\"NEXT_PUBLIC_RECAPTCHA_SITE_KEY\");\n\n/**\n * Recaptcha secret key for server-side token verification.\n * Used by verifyRecaptchaToken to call Google's siteverify endpoint.\n * Must NOT be exposed to the client (no NEXT_PUBLIC prefix).\n *\n * @example\n * const isValid = await verifyRecaptchaToken(token);\n */\nexport const RECAPTCHA_SECRET_KEY = getEnv(\"RECAPTCHA_SECRET_KEY\");\n\n/**\n * Slack webhook URLs for different log types.\n * Used for sending log messages to specific Slack channels based on log category.\n *\n * @property {string | undefined} ALERTS - Webhook for alert notifications\n * @property {string | undefined} CRON - Webhook for cron job logs\n * @property {string | undefined} LINKS - Webhook for link-related logs\n * @property {string | undefined} SUBSCRIBERS - Webhook for subscriber events\n * @property {string | undefined} ERRORS - Webhook for error logs\n *\n * @example\n * fetch(SLACK_WEBHOOKS.ALERTS, { method: 'POST', body: ... })\n */\nexport const SLACK_WEBHOOKS = {\n ALERTS: getEnv(\"SLACK_WEBHOOKS_HOOK_ALERTS\"),\n CRON: getEnv(\"SLACK_WEBHOOKS_HOOK_CRON\"),\n LINKS: getEnv(\"SLACK_WEBHOOKS_HOOK_LINKS\"),\n SUBSCRIBERS: getEnv(\"SLACK_WEBHOOKS_HOOK_SUBSCRIBERS\"),\n ERRORS: getEnv(\"SLACK_WEBHOOKS_HOOK_ERRORS\"),\n};\n\n/**\n * Default URL for Open Graph avatar images.\n * Used for generating user or entity avatars in OG images.\n *\n * @example\n * <img src={OG_AVATAR_URL + userId} />\n */\nexport const OG_AVATAR_URL = \"https://api.kumix.io/og/avatar/\";\n\n/**\n * Default pagination limit for API responses and UI lists.\n *\n * @example\n * const items = data.slice(0, PAGINATION_LIMIT);\n */\nexport const PAGINATION_LIMIT = 100;\n\n/**\n * Number of seconds in two weeks.\n * Useful for cookie expiration, session timeouts, etc.\n *\n * @example\n * cookie.set('token', value, { maxAge: TWO_WEEKS_IN_SECONDS });\n */\nexport const TWO_WEEKS_IN_SECONDS = 60 * 60 * 24 * 14;\n\n/**\n * The beginning of time for the application (arbitrary early date).\n * Used as a default value for date comparisons or migrations.\n *\n * @example\n * if (createdAt < THE_BEGINNING_OF_TIME) { ... }\n */\nexport const THE_BEGINNING_OF_TIME = new Date(\"2010-01-01T00:00:00.000Z\");\n\n/**\n * A large number used as a practical infinity in calculations.\n *\n * @example\n * if (count > INFINITY_NUMBER) { ... }\n */\nexport const INFINITY_NUMBER = 1000000000;\n\n/**\n * Query parameter name for redirection URLs.\n * Used to pass redirect destinations in authentication or navigation flows.\n *\n * @example\n * const url = `/login?${REDIRECTION_QUERY_PARAM}=/dashboard`;\n */\nexport const REDIRECT_QUERY_PARAM = \"redirectTo\";\n\n/**\n * LocalStorage key for storing the last visited workspace.\n * Used to persist user's last active workspace between sessions.\n */\nexport const LAST_VISITED_WORKSPACE = \"last-visited-workspace\";\n","/**\n * Constants for Framer Motion animations\n * Provides reusable animation presets for consistent UI motion\n */\n\n/**\n * Animation variants for list items\n * Creates a scale and fade effect for list items\n *\n * @example\n * ```tsx\n * import { motion } from 'framer-motion';\n * import { FRAMER_MOTION_LIST_ITEM_VARIANTS } from '@kumix/utils';\n *\n * // In a component\n * <motion.li\n * variants={FRAMER_MOTION_LIST_ITEM_VARIANTS}\n * initial=\"hidden\"\n * animate=\"show\"\n * >\n * List item content\n * </motion.li>\n * ```\n */\nexport const FRAMER_MOTION_LIST_ITEM_VARIANTS = {\n hidden: { scale: 0.8, opacity: 0 },\n show: { scale: 1, opacity: 1, transition: { type: \"spring\" } },\n};\n\n/**\n * Animation variants for staggered children elements\n * Creates a fade-in and slide-up effect with spring physics\n *\n * @example\n * ```tsx\n * import { motion } from 'framer-motion';\n * import { STAGGER_CHILD_VARIANTS } from '@kumix/utils';\n *\n * // In a parent component\n * <motion.ul\n * initial=\"hidden\"\n * animate=\"show\"\n * variants={{\n * show: {\n * transition: {\n * staggerChildren: 0.1\n * }\n * }\n * }}\n * >\n * {items.map(item => (\n * <motion.li key={item.id} variants={STAGGER_CHILD_VARIANTS}>\n * {item.content}\n * </motion.li>\n * ))}\n * </motion.ul>\n * ```\n */\nexport const STAGGER_CHILD_VARIANTS = {\n hidden: { opacity: 0, y: 20 },\n show: { opacity: 1, y: 0, transition: { duration: 0.4, type: \"spring\" } },\n};\n\n/**\n * Animation settings for tab items\n * Creates a smooth transition effect for tab switching\n *\n * @example\n * ```tsx\n * import { motion, AnimatePresence } from 'framer-motion';\n * import { TAB_ITEM_ANIMATION_SETTINGS } from '@kumix/utils';\n *\n * // In a component\n * <AnimatePresence mode=\"wait\">\n * <motion.div\n * key={activeTab}\n * {...TAB_ITEM_ANIMATION_SETTINGS}\n * >\n * {tabContent}\n * </motion.div>\n * </AnimatePresence>\n * ```\n */\nexport const TAB_ITEM_ANIMATION_SETTINGS = {\n initial: { opacity: 0, y: -10 },\n animate: { opacity: 1, y: 0 },\n exit: { opacity: 0, y: -10 },\n transition: { duration: 0.2, type: \"easeInOut\" },\n};\n","/**\n * Localhost Constants\n * Provides default geolocation and IP data for local development environments\n */\n\n/**\n * Default geolocation data for localhost/development environments\n * Used when actual geolocation data is unavailable or for testing location-based features\n *\n * @example\n * ```ts\n * import { LOCALHOST_GEO_DATA } from '@kumix/utils';\n *\n * // Use default geo data when in development environment\n * const geoData = isDevelopment ? LOCALHOST_GEO_DATA : userGeoData;\n *\n * // Testing location-based features\n * function getNearbyStores(userLocation = LOCALHOST_GEO_DATA) {\n * const { latitude, longitude } = userLocation;\n * // Implementation to find nearby stores\n * }\n * ```\n */\nexport const LOCALHOST_GEO_DATA = {\n continent: \"NA\",\n country: \"US\",\n city: \"San Francisco\",\n region: \"CA\",\n latitude: \"37.7695\",\n longitude: \"-122.385\",\n};\n\n/**\n * Default IP address for localhost/development environments\n * Used when actual IP data is unavailable or for testing IP-based features\n *\n * @example\n * ```ts\n * import { LOCALHOST_IP } from '@kumix/utils';\n *\n * // Use default IP when in development environment\n * const ipAddress = isDevelopment ? LOCALHOST_IP : userIpAddress;\n *\n * // Testing IP-based features\n * function getLocationFromIp(ip = LOCALHOST_IP) {\n * // Implementation to get location from IP\n * }\n * ```\n */\n// Use an RFC5737 TEST-NET address so dev/test IP lookups never hit a real\n// third-party service (the previous value 63.141.57.109 is a routable public\n// IP). TEST-NET 2 (198.51.100.0/24) is reserved for documentation/examples.\nexport const LOCALHOST_IP = \"198.51.100.1\";\n","/**\n * Reserved Slugs Constants\n * Provides a list of reserved slugs that cannot be used for user-generated content\n */\n\n/**\n * Array of reserved slugs that cannot be used as workspace slugs or custom paths\n * These are reserved for system use, existing routes, or to prevent confusion/abuse\n *\n * @example\n * ```ts\n * import { RESERVED_SLUGS } from '@kumix/utils';\n *\n * // Check if a slug is reserved\n * function isSlugReserved(slug: string) {\n * return RESERVED_SLUGS.includes(slug.toLowerCase());\n * }\n *\n * // Validate user input for custom workspace slug\n * function validateWorkspaceSlug(slug: string) {\n * if (RESERVED_SLUGS.includes(slug.toLowerCase())) {\n * return {\n * valid: false,\n * error: 'This slug is reserved. Please choose another one.'\n * };\n * }\n * return { valid: true };\n * }\n *\n * // Generate a unique slug that's not reserved\n * function generateUniqueSlug(baseName: string) {\n * let slug = baseName.toLowerCase().replace(/\\s+/g, '-');\n *\n * if (RESERVED_SLUGS.includes(slug)) {\n * // Append a random string or number if the slug is reserved\n * slug = `${slug}-${Math.random().toString(36).substring(2, 7)}`;\n * }\n *\n * return slug;\n * }\n * ```\n */\nexport const RESERVED_SLUGS = [\n /** 🔒 Platform reserved (root-level, system critical) */\n \"va\",\n \"static\",\n \"proxy\",\n \"robots\",\n \"robots.txt\",\n \"_next\",\n \"favicon\",\n \"sitemap\",\n \"error\",\n \"home\",\n \"app\",\n \"www\",\n\n /** 🧩 Marketing / public pages */\n \"about\",\n \"blog\",\n \"changelog\",\n \"careers\",\n \"contact\",\n \"demo\",\n \"docs\",\n \"features\",\n \"guides\",\n \"help\",\n \"info\",\n \"pricing\",\n \"privacy\",\n \"resources\",\n \"terms\",\n\n /** 🧭 Navigation / procedural flow */\n \"new\",\n \"invite\",\n \"invitation\",\n \"join\",\n \"accept\",\n \"verify\",\n \"onboarding\",\n\n /** 🌐 Social / external integrations */\n \"discord\",\n \"reddit\",\n\n /** 🧑‍💼 Auth routes */\n \"auth\",\n \"signin\",\n \"signout\",\n \"signup\",\n \"forgot-password\",\n \"reset-password\",\n \"recover-account\",\n \"magic-link\",\n \"email-otp\",\n \"two-factor\",\n \"2fa\",\n\n /** 🏢 Workspace / organization / user */\n \"account\",\n \"accounts\",\n \"billing\",\n \"billings\",\n \"organization\",\n \"organizations\",\n \"workspace\",\n \"workspaces\",\n \"setting\",\n \"settings\",\n \"domains\",\n\n /** 👥 Members / people */\n \"member\",\n \"members\",\n \"people\",\n \"peoples\",\n \"user\",\n \"users\",\n\n /** 🛠 API & integrations */\n \"api\",\n \"webhooks\",\n \"analytics\",\n \"metatags\",\n\n /** 📈 Business / revenue features */\n \"campaigns\",\n \"links\",\n \"events\",\n \"referrals\",\n \"upgrade\",\n \"wrapped\",\n \"invoices\",\n \"programs\",\n \"partners\",\n \"payouts\",\n \"commissions\",\n \"sales\",\n\n /** ⚙️ Admin / dashboard */\n \"admin\",\n \"dashboard\",\n];\n","/**\n * Google Analytics tracking utilities for React applications\n * Provides comprehensive event tracking with validation and error handling\n * Supports GA4 event structure and CRUD operations tracking\n *\n * DIFFERENCE FROM HOOKS/USE-ANALYTICS:\n * - This lib provides standalone utility functions for direct event tracking\n * - use-analytics hook provides React-specific state management and lifecycle integration\n * - This lib is for simple, direct GA tracking without React context\n * - use-analytics hook is for complex SaaS module tracking with React integration\n *\n * USE CASES:\n * - Use this lib for: Simple event tracking, non-React contexts, utility functions\n * - Use hooks for: Complex SaaS tracking, React components, state-dependent tracking\n */\n\nimport { logger } from \"../logging/logger\";\n\n/**\n * Interface for event tracking parameters\n * Defines the structure for tracking events in Google Analytics\n */\ninterface EventProps {\n /** Event name to be tracked (required, non-empty string) */\n name: string;\n /** Optional properties/attributes for the event */\n properties?: Record<string, string | number | boolean>;\n}\n\n/**\n * Global declaration for Google Analytics gtag function\n * This extends the Window interface to include the gtag function\n * that's injected by the Google Analytics script\n */\ndeclare global {\n interface Window {\n gtag?: (\n command: \"event\" | \"config\" | \"set\",\n targetId: string,\n config?: Record<string, string | number | boolean | object | null | undefined>,\n ) => void;\n }\n}\n\n/**\n * Tracks an event in Google Analytics with proper error handling and validation.\n *\n * @param params - Event parameters\n * @param params.name - Event name (required, non-empty string)\n * @param params.properties - Optional event properties\n */\nexport const googleTrackEvent = ({ name, properties }: EventProps) => {\n // Validate required parameters\n if (!name || typeof name !== \"string\" || name.trim().length === 0) {\n logger.warn(\"Analytics: Event name is required and must be a non-empty string\");\n return;\n }\n\n // Validate properties if provided\n if (properties && typeof properties !== \"object\") {\n logger.warn(\"Analytics: Properties must be an object\");\n return;\n }\n\n try {\n // Track in Google Analytics\n if (typeof window !== \"undefined\" && window.gtag) {\n // GA4 recommended event structure\n window.gtag(\"event\", name.trim(), {\n ...properties,\n // GA4 recommended parameters\n event_category: properties?.category || \"engagement\",\n event_label: properties?.label,\n value: properties?.value,\n });\n }\n } catch (error) {\n logger.error(\"Analytics: Failed to track event\", { name, error });\n }\n};\n\n/**\n * Helper function to safely get the first path segment (component category)\n * from a component path. For \"ui/buttons/Button\" this returns \"ui\".\n *\n * @param componentPath - Component path string\n * @returns First segment of the path, or \"unknown\" if invalid\n */\nconst getComponentName = (componentPath: string): string => {\n if (!componentPath || typeof componentPath !== \"string\") {\n return \"unknown\";\n }\n const trimmed = componentPath.trim();\n if (!trimmed) return \"unknown\";\n const firstSlash = trimmed.indexOf(\"/\");\n return firstSlash === -1 ? trimmed : trimmed.slice(0, firstSlash);\n};\n\n/**\n * Tracks code copy events with validation.\n *\n * @param componentPath - Path of the component where code was copied\n */\nexport const googleTrackCodeCopy = (componentPath: string) => {\n if (!componentPath || typeof componentPath !== \"string\") {\n logger.warn(\"Analytics: componentPath is required for trackCodeCopy\");\n return;\n }\n\n const componentName = getComponentName(componentPath);\n googleTrackEvent({\n name: \"doc_copy\",\n properties: {\n component_name: componentName,\n content_type: \"code\",\n category: \"engagement\",\n label: `Code Copy - ${componentPath.trim()}`,\n },\n });\n};\n\n/**\n * Tracks theme mode changes with validation.\n *\n * @param componentPath - Path of the component where theme was changed\n * @param newTheme - New theme mode ('dark' or 'light')\n */\nexport const googleTrackThemeChange = (componentPath: string, newTheme: \"dark\" | \"light\") => {\n if (!componentPath || typeof componentPath !== \"string\") {\n logger.warn(\"Analytics: componentPath is required for trackThemeChange\");\n return;\n }\n\n if (!newTheme || ![\"dark\", \"light\"].includes(newTheme)) {\n logger.warn('Analytics: newTheme must be either \"dark\" or \"light\"');\n return;\n }\n\n const componentName = getComponentName(componentPath);\n googleTrackEvent({\n name: \"doc_select_theme\",\n properties: {\n component_name: componentName,\n theme_mode: newTheme,\n category: \"engagement\",\n label: `Theme Change - ${componentPath.trim()}`,\n },\n });\n};\n\n/**\n * Tracks text direction changes with validation.\n *\n * @param componentPath - Path of the component where direction was changed\n * @param newDirection - New text direction ('rtl' or 'ltr')\n */\nexport const googleTrackDirectionChange = (componentPath: string, newDirection: \"rtl\" | \"ltr\") => {\n if (!componentPath || typeof componentPath !== \"string\") {\n logger.warn(\"Analytics: componentPath is required for trackDirectionChange\");\n return;\n }\n\n if (!newDirection || ![\"rtl\", \"ltr\"].includes(newDirection)) {\n logger.warn('Analytics: newDirection must be either \"rtl\" or \"ltr\"');\n return;\n }\n\n const componentName = getComponentName(componentPath);\n googleTrackEvent({\n name: \"doc_select_direction\",\n properties: {\n component_name: componentName,\n text_direction: newDirection,\n category: \"engagement\",\n label: `Direction Change - ${componentPath.trim()}`,\n },\n });\n};\n\n/**\n * Tracks view mode changes with validation.\n *\n * @param componentPath - Path of the component where view was changed\n * @param newView - New view mode ('preview' or 'code')\n */\nexport const googleTrackViewChange = (componentPath: string, newView: \"preview\" | \"code\") => {\n if (!componentPath || typeof componentPath !== \"string\") {\n logger.warn(\"Analytics: componentPath is required for trackViewChange\");\n return;\n }\n\n if (!newView || ![\"preview\", \"code\"].includes(newView)) {\n logger.warn('Analytics: newView must be either \"preview\" or \"code\"');\n return;\n }\n\n const componentName = getComponentName(componentPath);\n googleTrackEvent({\n name: \"doc_select_view\",\n properties: {\n component_name: componentName,\n view_mode: newView,\n category: \"engagement\",\n label: `View Change - ${componentPath.trim()}`,\n },\n });\n};\n\n/**\n * Tracks item creation events with validation.\n *\n * @param module - Module name where item was created\n * @param itemType - Type of item created\n * @param itemId - Optional ID of the created item\n */\nexport const googleTrackItemCreate = (\n module: string,\n itemType: string,\n itemId?: string | number,\n) => {\n if (!module || typeof module !== \"string\" || module.trim().length === 0) {\n logger.warn(\"Analytics: module is required for trackItemCreate\");\n return;\n }\n\n if (!itemType || typeof itemType !== \"string\" || itemType.trim().length === 0) {\n logger.warn(\"Analytics: itemType is required for trackItemCreate\");\n return;\n }\n\n googleTrackEvent({\n name: \"crud_create\",\n properties: {\n module: module.trim(),\n item_type: itemType.trim(),\n ...(itemId && { item_id: itemId.toString() }),\n category: \"crud\",\n label: `Create ${itemType.trim()} - ${module.trim()}`,\n },\n });\n};\n\n/**\n * Tracks item view/read events with validation.\n *\n * @param module - Module name where item was viewed\n * @param itemType - Type of item viewed\n * @param itemId - ID of the viewed item\n */\nexport const googleTrackItemView = (module: string, itemType: string, itemId: string | number) => {\n if (!module || typeof module !== \"string\" || module.trim().length === 0) {\n logger.warn(\"Analytics: module is required for trackItemView\");\n return;\n }\n\n if (!itemType || typeof itemType !== \"string\" || itemType.trim().length === 0) {\n logger.warn(\"Analytics: itemType is required for trackItemView\");\n return;\n }\n\n if (itemId === undefined || itemId === null || itemId === \"\") {\n logger.warn(\"Analytics: itemId is required for trackItemView\");\n return;\n }\n\n googleTrackEvent({\n name: \"crud_view\",\n properties: {\n module: module.trim(),\n item_type: itemType.trim(),\n item_id: itemId.toString(),\n category: \"crud\",\n label: `View ${itemType.trim()} - ${module.trim()}`,\n },\n });\n};\n\n/**\n * Tracks item update events with validation.\n *\n * @param module - Module name where item was updated\n * @param itemType - Type of item updated\n * @param itemId - ID of the updated item\n */\nexport const googleTrackItemUpdate = (\n module: string,\n itemType: string,\n itemId: string | number,\n) => {\n if (!module || typeof module !== \"string\" || module.trim().length === 0) {\n logger.warn(\"Analytics: module is required for trackItemUpdate\");\n return;\n }\n\n if (!itemType || typeof itemType !== \"string\" || itemType.trim().length === 0) {\n logger.warn(\"Analytics: itemType is required for trackItemUpdate\");\n return;\n }\n\n if (itemId === undefined || itemId === null || itemId === \"\") {\n logger.warn(\"Analytics: itemId is required for trackItemUpdate\");\n return;\n }\n\n googleTrackEvent({\n name: \"crud_update\",\n properties: {\n module: module.trim(),\n item_type: itemType.trim(),\n item_id: itemId.toString(),\n category: \"crud\",\n label: `Update ${itemType.trim()} - ${module.trim()}`,\n },\n });\n};\n\n/**\n * Tracks item delete events with validation.\n *\n * @param module - Module name where item was deleted\n * @param itemType - Type of item deleted\n * @param itemId - ID of the deleted item\n * @param isHardDelete - Whether this is a hard delete (permanent) or soft delete\n */\nexport const googleTrackItemDelete = (\n module: string,\n itemType: string,\n itemId: string | number,\n isHardDelete: boolean = false,\n) => {\n if (!module || typeof module !== \"string\" || module.trim().length === 0) {\n logger.warn(\"Analytics: module is required for trackItemDelete\");\n return;\n }\n\n if (!itemType || typeof itemType !== \"string\" || itemType.trim().length === 0) {\n logger.warn(\"Analytics: itemType is required for trackItemDelete\");\n return;\n }\n\n if (itemId === undefined || itemId === null || itemId === \"\") {\n logger.warn(\"Analytics: itemId is required for trackItemDelete\");\n return;\n }\n\n googleTrackEvent({\n name: \"crud_delete\",\n properties: {\n module: module.trim(),\n item_type: itemType.trim(),\n item_id: itemId.toString(),\n delete_type: isHardDelete ? \"hard\" : \"soft\",\n category: \"crud\",\n label: `Delete ${itemType.trim()} - ${module.trim()}`,\n },\n });\n};\n\n/**\n * Tracks item restore events with validation.\n *\n * @param module - Module name where item was restored\n * @param itemType - Type of item restored\n * @param itemId - ID of the restored item\n */\nexport const googleTrackItemRestore = (\n module: string,\n itemType: string,\n itemId: string | number,\n) => {\n if (!module || typeof module !== \"string\" || module.trim().length === 0) {\n logger.warn(\"Analytics: module is required for trackItemRestore\");\n return;\n }\n\n if (!itemType || typeof itemType !== \"string\" || itemType.trim().length === 0) {\n logger.warn(\"Analytics: itemType is required for trackItemRestore\");\n return;\n }\n\n if (itemId === undefined || itemId === null || itemId === \"\") {\n logger.warn(\"Analytics: itemId is required for trackItemRestore\");\n return;\n }\n\n googleTrackEvent({\n name: \"crud_restore\",\n properties: {\n module: module.trim(),\n item_type: itemType.trim(),\n item_id: itemId.toString(),\n category: \"crud\",\n label: `Restore ${itemType.trim()} - ${module.trim()}`,\n },\n });\n};\n","/**\n * Utility function for array manipulation\n * Provides a way to split arrays into smaller chunks of specified size\n */\n\n/**\n * Splits an array into smaller chunks of a specified size\n * Useful for pagination, batch processing, or creating grid layouts\n *\n * @param array - The array to be chunked\n * @param chunk_size - The size of each chunk\n * @returns A new array containing chunks of the original array\n *\n * @example\n * ```ts\n * // Basic usage\n * chunk([1, 2, 3, 4, 5, 6, 7, 8], 3)\n * // Returns [[1, 2, 3], [4, 5, 6], [7, 8]]\n *\n * // With string array\n * chunk(['a', 'b', 'c', 'd', 'e'], 2)\n * // Returns [['a', 'b'], ['c', 'd'], ['e']]\n *\n * // With objects\n * const users = [\n * { id: 1, name: 'Alice' },\n * { id: 2, name: 'Bob' },\n * { id: 3, name: 'Charlie' },\n * { id: 4, name: 'Dave' }\n * ];\n * chunk(users, 2)\n * // Returns [\n * // [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }],\n * // [{ id: 3, name: 'Charlie' }, { id: 4, name: 'Dave' }]\n * // ]\n *\n * // Empty array returns empty array\n * chunk([], 3)\n * // Returns []\n * ```\n */\nexport const chunk = <T>(array: T[], chunk_size: number): T[][] => {\n if (chunk_size <= 0) return [];\n return array.reduce((resultArray, item, index) => {\n const chunkIndex = Math.floor(index / chunk_size);\n\n if (!resultArray[chunkIndex]) {\n resultArray[chunkIndex] = []; // start a new chunk\n }\n\n resultArray[chunkIndex].push(item);\n\n return resultArray;\n }, [] as T[][]);\n};\n","/**\n * Utility function for random selection\n * Provides a simple way to select a random element from an array\n */\n\n/**\n * Selects a random element from an array\n * Returns undefined if the array is empty\n *\n * @param values - The array to select a random element from\n * @returns A random element from the array, or undefined if the array is empty\n *\n * @example\n * ```ts\n * import { randomValue } from '@/utils/functions';\n *\n * // Basic usage with strings\n * const colors = ['red', 'green', 'blue', 'yellow'];\n * const randomColor = randomValue(colors);\n * // Returns a random color from the array\n *\n * // With numbers\n * const randomNumber = randomValue([1, 2, 3, 4, 5]);\n * // Returns a random number from the array\n *\n * // With objects\n * const users = [\n * { id: 1, name: 'Alice' },\n * { id: 2, name: 'Bob' },\n * { id: 3, name: 'Charlie' }\n * ];\n * const randomUser = randomValue(users);\n * // Returns a random user object from the array\n *\n * // Handle empty array\n * const empty = [];\n * const result = randomValue(empty);\n * // Returns undefined\n *\n * // Type-safe with generics\n * const randomItem = randomValue<string>(['a', 'b', 'c']);\n * // TypeScript knows this is a string\n * ```\n */\nexport const randomValue = <T>(values: T[]): T | undefined => {\n if (values.length === 0) return undefined;\n return values[Math.floor(Math.random() * values.length)];\n};\n","/**\n * Utility function for stable array sorting\n * Provides a way to sort arrays while preserving the original order of equal elements\n */\n\n/**\n * Sorts an array using the specified compare function, preserving the order\n * of elements that compare equally (stable sort)\n *\n * @param arr - The array to sort\n * @param compare - The comparison function that returns negative, zero, or positive values\n * @returns A new sorted array with the original order of equal elements preserved\n *\n * @example\n * ```ts\n * import { stableSort } from '@/utils/functions';\n *\n * // Basic usage with numbers\n * const numbers = [3, 1, 4, 1, 5, 9];\n * const sortedNumbers = stableSort(numbers, (a, b) => a - b);\n * // Returns [1, 1, 3, 4, 5, 9] with the first \"1\" still coming before the second \"1\"\n *\n * // With objects and multiple sort criteria\n * const users = [\n * { name: 'Alice', role: 'admin', id: 1 },\n * { name: 'Bob', role: 'user', id: 2 },\n * { name: 'Charlie', role: 'user', id: 3 },\n * { name: 'David', role: 'admin', id: 4 }\n * ];\n *\n * // Sort by role first, then by original order\n * const sortedUsers = stableSort(users, (a, b) =>\n * a.role.localeCompare(b.role)\n * );\n * // The order of users with the same role is preserved\n * ```\n */\nexport const stableSort = <T>(arr: T[], compare: (a: T, b: T) => number): T[] =>\n arr\n .map((item, index) => ({ item, index }))\n .sort((a, b) => compare(a.item, b.item) || a.index - b.index)\n .map(({ item }) => item);\n","/**\n * Asset URL builder utilities\n * Provides helpers to construct absolute asset URLs against a configurable asset host.\n */\n\nimport { getEnv } from \"../../env\";\n\nconst DEFAULT_ASSET_HOST =\n getEnv(\"NEXT_PUBLIC_ASSETS_URL\") || getEnv(\"VITE_ASSETS_URL\") || \"https://assets.kumix.io\";\n\n/**\n * Builds an absolute URL for a given asset path using the provided asset host (CDN) base.\n * Accepts relative paths (e.g., `logo/logo.png`, `/images/icon.svg`) and returns a fully-qualified URL.\n * If an absolute URL is provided as `path`, it will be returned as-is (host is ignored).\n *\n * @param path - Asset path or absolute URL to resolve\n * @param host - Optional asset host (base URL). Defaults to `https://assets.kumix.io`\n * @returns A fully-qualified asset URL string. On invalid input (empty path or\n * malformed base), falls back to the configured asset host rather than\n * throwing — call sites that need strict failure should validate inputs first.\n *\n * @example\n * ```ts\n * import { assetsUrl } from '@/lib/assets';\n *\n * // Default host\n * const u1 = assetsUrl('logo/logo.png');\n * // 'https://assets.kumix.io/logo/logo.png'\n *\n * // Custom host (full URL)\n * const u2 = assetsUrl('/images/icon.svg', 'https://cdn.example.com');\n * // 'https://cdn.example.com/images/icon.svg'\n *\n * // Custom host (without protocol) — will be normalized to https://\n * const u3 = assetsUrl('icons/search.svg', 'cdn.example.com');\n * // 'https://cdn.example.com/icons/search.svg'\n *\n * // Absolute path passes through (host is ignored)\n * const u4 = assetsUrl('https://other.com/a.png', 'https://cdn.example.com');\n * // 'https://other.com/a.png'\n *\n * // Edge cases — falsy path or malformed base returns the configured asset host\n * const u5 = assetsUrl('');\n * // 'https://assets.kumix.io' (the configured host)\n *\n * const u6 = assetsUrl('logo.png', '://bad-host');\n * // '://bad-host' (the supplied host — invalid, returned as-is)\n * ```\n */\nexport function assetsUrl(path: string, host: string = DEFAULT_ASSET_HOST): string {\n const env = getEnv(\"NEXT_PUBLIC_ASSETS_URL\") || getEnv(\"VITE_ASSETS_URL\");\n const BASE_HOST = env ?? host;\n\n if (!path || typeof path !== \"string\") {\n return BASE_HOST;\n }\n\n try {\n // Normalize BASE_HOST if given without protocol, e.g., \"cdn.example.com\"\n const base = /^https?:\\/\\//i.test(BASE_HOST) ? BASE_HOST : `https://${BASE_HOST}`;\n const url = new URL(path, base); // absolute `path` will override `base`\n return url.toString();\n } catch {\n return BASE_HOST;\n }\n}\n\n/**\n * Build a CDN URL for a country flag SVG.\n *\n * The function lowercases the given ISO country code and returns a\n * fully-qualified URL pointing to the SVG flag hosted on the Kumix\n * assets CDN.\n *\n * @param flag - ISO 3166-1 alpha-2 country code (e.g., \"US\", \"ID\", \"GB\")\n * @returns A URL string to the SVG flag on the CDN\n *\n * @example\n * ```ts\n * import { getFlagUrl } from \"@kumix/ui/utils/flag-url\";\n *\n * const urlUs = getFlagUrl(\"US\");\n * // \"https://assets.kumix.io/media/flags/us.svg\"\n *\n * const urlId = getFlagUrl(\"id\");\n * // \"https://assets.kumix.io/media/flags/id.svg\"\n *\n * // Can be used directly in an <img /> or <Image /> component\n * // <img src={getFlagUrl(\"GB\")} alt=\"United Kingdom flag\" />\n * ```\n */\nexport function getFlagUrl(flag: string): string {\n // Guard against null/undefined/empty/non-string inputs — without this the\n // `.toLowerCase()` call throws and a bad flag code would otherwise produce a\n // malformed \".../.svg\" URL. Fall back to a deterministic placeholder.\n if (typeof flag !== \"string\" || !flag.trim()) {\n return `${assetsUrl(\"media/flags\")}/unknown.svg`;\n }\n const flagCode = flag.trim().toLowerCase();\n\n return `${assetsUrl(\"media/flags\")}/${flagCode}.svg`;\n}\n","/**\n * Browser metadata construction utilities\n * Provides functions for building SEO-optimized metadata for Next.js applications\n */\n\nimport { assetsUrl } from \"../string/assets\";\n\nexport type metadataProps = {\n baseUrl?: string;\n title?: string;\n fullTitle?: string;\n description?: string;\n // biome-ignore lint/suspicious/noExplicitAny: disable\n icons?: Array<Record<string, any>>;\n url?: string;\n image?: string | null;\n video?: string | null;\n openGraph?: {\n type?:\n | \"website\"\n | \"article\"\n | \"book\"\n | \"profile\"\n | \"music.song\"\n | \"music.album\"\n | \"music.playlist\"\n | \"music.radio_station\"\n | \"video.movie\"\n | \"video.episode\"\n | \"video.tv_show\"\n | \"video.other\";\n locale?: string;\n name?: string;\n };\n twitter?: {\n site?: string;\n creator?: string;\n };\n canonicalUrl?: string;\n alternateLanguages?: Record<string, string>;\n noIndex?: boolean;\n noArchive?: boolean;\n noSnippet?: boolean;\n manifest?: string | URL | null;\n};\n\n/**\n * Helper to map short locale codes to Open Graph/SEO locale format\n * @param locale - Short locale code (e.g., 'en', 'id', 'ar', 'zh')\n * @returns Open Graph locale string (e.g., 'en_US', 'id_ID', 'ar_AR', 'zh_CN')\n */\nexport function mapLocale(locale?: string): string | undefined {\n if (!locale) return \"en_US\";\n\n const mapping: Record<string, string> = {\n af: \"af_ZA\", // Afrikaans - South Africa\n am: \"am_ET\", // Amharic - Ethiopia\n ar: \"ar_AR\", // Arabic - Saudi Arabia\n bn: \"bn_BD\", // Bengali - Bangladesh\n bg: \"bg_BG\", // Bulgarian - Bulgaria\n cs: \"cs_CZ\", // Czech - Czech Republic\n da: \"da_DK\", // Danish - Denmark\n de: \"de_DE\", // German - Germany\n el: \"el_GR\", // Greek - Greece\n en: \"en_US\", // English - United States\n en_uk: \"en_GB\", // English - United Kingdom\n es: \"es_ES\", // Spanish - Spain\n es_mx: \"es_MX\", // Spanish - Mexico\n fa: \"fa_IR\", // Persian/Farsi - Iran\n fi: \"fi_FI\", // Finnish - Finland\n fr: \"fr_FR\", // French - France\n fr_ca: \"fr_CA\", // French - Canada\n he: \"he_IL\", // Hebrew - Israel\n hi: \"hi_IN\", // Hindi - India\n hr: \"hr_HR\", // Croatian - Croatia\n hu: \"hu_HU\", // Hungarian - Hungary\n id: \"id_ID\", // Indonesian - Indonesia\n it: \"it_IT\", // Italian - Italy\n ja: \"ja_JP\", // Japanese - Japan\n ko: \"ko_KR\", // Korean - South Korea\n ms: \"ms_MY\", // Malay - Malaysia\n nl: \"nl_NL\", // Dutch - Netherlands\n no: \"nb_NO\", // Norwegian Bokmål - Norway\n pl: \"pl_PL\", // Polish - Poland\n pt: \"pt_PT\", // Portuguese - Portugal\n pt_br: \"pt_BR\", // Portuguese - Brazil\n ro: \"ro_RO\", // Romanian - Romania\n ru: \"ru_RU\", // Russian - Russia\n sk: \"sk_SK\", // Slovak - Slovakia\n sr: \"sr_RS\", // Serbian - Serbia\n sv: \"sv_SE\", // Swedish - Sweden\n sw: \"sw_KE\", // Swahili - Kenya\n th: \"th_TH\", // Thai - Thailand\n tl: \"tl_PH\", // Filipino/Tagalog - Philippines\n tr: \"tr_TR\", // Turkish - Türkiye\n uk: \"uk_UA\", // Ukrainian - Ukraine\n ur: \"ur_PK\", // Urdu - Pakistan\n vi: \"vi_VN\", // Vietnamese - Vietnam\n zh: \"zh_CN\", // Chinese (Simplified) - China\n zh_hk: \"zh_HK\", // Chinese (Traditional) - Hong Kong\n zh_tw: \"zh_TW\", // Chinese (Traditional) - Taiwan\n };\n\n return mapping[locale] || locale;\n}\n\n/**\n * Constructs a metadata object for Next.js pages, suitable for SEO and social sharing.\n * Supports Open Graph, Twitter cards, icons, canonical URLs, robots, manifest, and multi-language alternates.\n *\n * @param params - Metadata construction options\n * @param params.baseUrl - The base URL/domain for metadataBase (optional, e.g., 'https://kumix.io')\n * @param params.title - The base title for the page (used in Open Graph and Twitter)\n * @param params.fullTitle - The full title for the page (overrides title in the <title> tag)\n * @param params.description - Description of the page (used in meta, Open Graph, Twitter)\n * @param params.icons - Icons for the page (favicon, apple-touch-icon, mask-icon, etc.)\n * @param params.url - The canonical URL of the page (used in Open Graph, canonical)\n * @param params.image - URL of the image for social sharing (Open Graph, Twitter)\n * @param params.video - URL of the video for social sharing (Open Graph, Twitter)\n * @param params.openGraph - Open Graph options (object: type, locale, name)\n * @param params.openGraph.type - Open Graph type (e.g., 'website', 'article', etc.)\n * @param params.openGraph.locale - Open Graph locale (e.g., 'en_US', 'id_ID')\n * @param params.openGraph.name - Open Graph site name (e.g., 'Kumix')\n * @param params.twitter - Twitter card options (object: site, creator)\n * @param params.twitter.site - Twitter @username for the site\n * @param params.twitter.creator - Twitter @username for the creator\n * @param params.canonicalUrl - Alternate canonical URL (used if url is not provided)\n * @param params.alternateLanguages - Object of language codes to URLs for alternate language versions\n * @param params.noIndex - If true, sets robots meta to noindex, nofollow (default: false)\n * @param params.noArchive - If true, sets robots meta to noarchive (default: false)\n * @param params.noSnippet - If true, sets robots meta to nosnippet (default: false)\n * @param params.manifest - URL or path to the web app manifest\n * @returns Metadata object compatible with Next.js <head> and SEO best practices\n *\n * @example\n * ```ts\n * import { constructMetadata } from '@/utils/functions';\n *\n * // Basic page metadata\n * const metadata = constructMetadata({\n * title: 'Home',\n * fullTitle: 'Kumix - Home',\n * description: 'Welcome to Kumix',\n * image: assetsUrl('og-image.png'),\n * url: '/home',\n * openGraph: {\n * type: 'website',\n * locale: 'en_US',\n * name: 'Kumix',\n * },\n * twitter: {\n * site: '@kumix',\n * creator: '@lukmanaviccena',\n * },\n * alternateLanguages: {\n * en: 'https://kumix.io/en',\n * id: 'https://kumix.io/id',\n * },\n * icons: [\n * { rel: 'icon', url: '/favicon.ico' },\n * { rel: 'mask-icon', url: '/safari-pinned-tab.svg', color: '#5bbad5' },\n * ],\n * });\n *\n * // Article metadata\n * const articleMetadata = constructMetadata({\n * title: 'How to Build Better Apps',\n * description: 'Learn the best practices for building modern web applications',\n * image: assetsUrl('articles/build-better-apps.pn'),\n * url: '/blog/build-better-apps',\n * openGraph: {\n * type: 'article',\n * locale: 'en_US',\n * name: 'Kumix Blog',\n * },\n * });\n *\n * // Product page metadata\n * const productMetadata = constructMetadata({\n * title: 'Premium Plan',\n * description: 'Unlock advanced features with our premium plan',\n * image: assetsUrl('products/premium.png'),\n * url: '/pricing/premium',\n * noIndex: false,\n * manifest: '/manifest.json',\n * });\n * ```\n */\nexport function constructMetadata({\n baseUrl,\n title,\n fullTitle,\n description,\n icons = [\n {\n rel: \"apple-touch-icon\",\n sizes: \"32x32\",\n url: assetsUrl(\"favicon/apple-touch-icon.png\"),\n },\n {\n rel: \"icon\",\n type: \"image/png\",\n sizes: \"32x32\",\n url: assetsUrl(\"favicon/favicon-32x32.png\"),\n },\n {\n rel: \"icon\",\n type: \"image/png\",\n sizes: \"16x16\",\n url: assetsUrl(\"favicon/favicon-16x16.png\"),\n },\n ],\n image,\n video,\n url,\n openGraph = {\n type: \"website\",\n locale: \"en_US\",\n },\n twitter = {},\n canonicalUrl,\n alternateLanguages,\n noIndex = false,\n noArchive = false,\n noSnippet = false,\n manifest,\n // biome-ignore lint/suspicious/noExplicitAny: disable\n}: metadataProps): Record<string, any> {\n // Build metadataBase defensively: a malformed baseUrl (common in dev, e.g.\n // NEXT_PUBLIC_SITE_URL=\"localhost:3000\" without protocol) used to throw and\n // 500 the page during Next.js metadata construction. Fall back to undefined.\n let metadataBase: URL | undefined;\n if (baseUrl) {\n try {\n metadataBase = new URL(baseUrl);\n } catch {\n metadataBase = undefined;\n }\n }\n\n return {\n metadataBase,\n title: fullTitle || title,\n description,\n icons,\n openGraph: {\n title,\n description,\n type: openGraph.type ?? \"website\",\n locale: mapLocale(openGraph.locale),\n ...(openGraph.name && {\n siteName: openGraph.name,\n }),\n url,\n ...(image && {\n images: image,\n }),\n ...(video && {\n videos: video,\n }),\n },\n twitter: {\n title,\n description,\n ...(image && {\n card: \"summary_large_image\",\n images: [image],\n }),\n ...(video && {\n player: video,\n }),\n ...(twitter.site && {\n site: twitter.site,\n }),\n ...(twitter.creator && {\n creator: twitter.creator,\n }),\n },\n ...((url || canonicalUrl || alternateLanguages) && {\n alternates: {\n ...(url || canonicalUrl ? { canonical: url || canonicalUrl } : {}),\n ...(alternateLanguages ? { languages: alternateLanguages } : {}),\n },\n }),\n ...((noIndex || noArchive || noSnippet) && {\n robots: {\n ...(noIndex ? { index: false, follow: false } : {}),\n ...(noArchive ? { noarchive: true } : {}),\n ...(noSnippet ? { nosnippet: true } : {}),\n },\n }),\n ...(manifest && {\n manifest,\n }),\n creator: \"lukmanaviccena\",\n };\n}\n","/**\n * Browser cookies utilities\n * Provides safe cookie operations with error handling and type safety\n * Works in both client-side and server-side environments\n */\n\nimport { logger } from \"../logging/logger\";\n\n/**\n * Interface for cookie options\n */\ninterface CookieOptions {\n /** Expiration time in days */\n expires?: number;\n /** Cookie path */\n path?: string;\n /** Cookie domain */\n domain?: string;\n /** Secure flag (HTTPS only) */\n secure?: boolean;\n /** SameSite attribute */\n sameSite?: \"strict\" | \"lax\" | \"none\";\n /** HttpOnly flag (server-side only) */\n httpOnly?: boolean;\n}\n\n/**\n * Interface for cookie value with metadata\n */\ninterface CookieValue<T = unknown> {\n /** The actual value */\n value: T;\n /** Timestamp when the cookie was set */\n timestamp: number;\n /** Optional version for data migration */\n version?: string;\n}\n\n/**\n * Sets a cookie with the specified name, value, and options\n * Automatically handles JSON serialization and error cases\n *\n * @param name - The name of the cookie\n * @param value - The value to store (will be JSON stringified)\n * @param options - Cookie options like expiration, path, domain, etc.\n * @returns True if the cookie was set successfully, false otherwise\n *\n * @example\n * ```typescript\n * import { setCookie } from '@kumix/utils';\n *\n * // Basic usage\n * setCookie('username', 'john_doe');\n *\n * // With expiration (7 days)\n * setCookie('auth_token', 'abc123', { expires: 7 });\n *\n * // With full options\n * setCookie('user_preferences', { theme: 'dark', lang: 'en' }, {\n * expires: 30,\n * path: '/',\n * secure: true,\n * sameSite: 'strict'\n * });\n *\n * // Store complex objects\n * setCookie('cart_items', [\n * { id: 1, name: 'Product A', quantity: 2 },\n * { id: 2, name: 'Product B', quantity: 1 }\n * ], { expires: 1 });\n *\n * // Session cookie (expires when browser closes)\n * setCookie('session_id', 'sess_123456');\n *\n * // Secure cookie for sensitive data\n * setCookie('csrf_token', 'token_abc', {\n * secure: true,\n * sameSite: 'strict',\n * httpOnly: true // Server-side only\n * });\n * ```\n */\nexport const setCookie = <T>(name: string, value: T, options: CookieOptions = {}): boolean => {\n if (typeof document === \"undefined\") {\n logger.warn(\"setCookie: Document is not available (SSR environment)\");\n return false;\n }\n\n try {\n const cookieValue: CookieValue<T> = {\n value,\n timestamp: Date.now(),\n version: \"1.0\",\n };\n\n const serializedValue = JSON.stringify(cookieValue);\n let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(serializedValue)}`;\n\n // Add expiration\n if (options.expires) {\n const expirationDate = new Date();\n expirationDate.setTime(expirationDate.getTime() + options.expires * 24 * 60 * 60 * 1000);\n cookieString += `; expires=${expirationDate.toUTCString()}`;\n }\n\n // Add path\n if (options.path) {\n cookieString += `; path=${options.path}`;\n }\n\n // Add domain\n if (options.domain) {\n cookieString += `; domain=${options.domain}`;\n }\n\n // Add secure flag\n if (options.secure) {\n cookieString += \"; secure\";\n }\n\n // Add SameSite\n if (options.sameSite) {\n cookieString += `; samesite=${options.sameSite}`;\n }\n\n // Add HttpOnly (note: this won't work in client-side JS, only server-side)\n if (options.httpOnly) {\n cookieString += \"; httponly\";\n }\n\n // biome-ignore lint/suspicious/noDocumentCookie: Legacy cookie API needed for broader browser compatibility\n document.cookie = cookieString;\n\n logger.debug(\"Cookie set successfully\", { name, options });\n return true;\n } catch (error) {\n logger.error(\"Failed to set cookie\", { name, error });\n return false;\n }\n};\n\n/**\n * Gets a cookie value by name with automatic JSON parsing\n * Returns null if the cookie doesn't exist or cannot be parsed\n *\n * @param name - The name of the cookie to retrieve\n * @returns The parsed cookie value or null if not found/invalid\n *\n * @example\n * ```typescript\n * import { getCookie } from '@kumix/utils';\n *\n * // Get simple value\n * const username = getCookie<string>('username');\n * if (username) {\n * console.log('Welcome back,', username);\n * }\n *\n * // Get complex object\n * const preferences = getCookie<{ theme: string; lang: string }>('user_preferences');\n * if (preferences) {\n * applyTheme(preferences.theme);\n * setLanguage(preferences.lang);\n * }\n *\n * // Get array data\n * const cartItems = getCookie<CartItem[]>('cart_items');\n * if (cartItems) {\n * updateCartDisplay(cartItems);\n * }\n *\n * // With default value\n * const theme = getCookie<string>('theme') || 'light';\n *\n * // Check if user is authenticated\n * const authToken = getCookie<string>('auth_token');\n * const isAuthenticated = !!authToken;\n *\n * // Get with type safety\n * interface UserSession {\n * userId: string;\n * role: string;\n * expiresAt: number;\n * }\n * const session = getCookie<UserSession>('user_session');\n * if (session && session.expiresAt > Date.now()) {\n * // Session is valid\n * authenticateUser(session);\n * }\n * ```\n */\nexport const getCookie = <T = unknown>(name: string): T | null => {\n if (typeof document === \"undefined\") {\n logger.warn(\"getCookie: Document is not available (SSR environment)\");\n return null;\n }\n\n try {\n const nameEQ = `${encodeURIComponent(name)}=`;\n const cookies = document.cookie.split(\";\");\n\n for (let cookie of cookies) {\n cookie = cookie.trim();\n if (cookie.indexOf(nameEQ) === 0) {\n const cookieValue = decodeURIComponent(cookie.substring(nameEQ.length));\n\n try {\n const parsed: CookieValue<T> = JSON.parse(cookieValue);\n logger.debug(\"Cookie retrieved successfully\", {\n name,\n timestamp: parsed.timestamp,\n version: parsed.version,\n });\n return parsed.value;\n } catch (_parseError) {\n // Fallback for cookies set without our wrapper\n logger.debug(\"Cookie found but not in expected format, returning raw value\", {\n name,\n });\n return cookieValue as T;\n }\n }\n }\n\n logger.debug(\"Cookie not found\", { name });\n return null;\n } catch (error) {\n logger.error(\"Failed to get cookie\", { name, error });\n return null;\n }\n};\n\n/**\n * Removes a cookie by setting its expiration date to the past\n * Optionally specify path and domain to ensure proper removal\n *\n * @param name - The name of the cookie to remove\n * @param options - Options for path and domain (should match the original cookie)\n * @returns True if the removal was attempted successfully, false otherwise\n *\n * @example\n * ```typescript\n * import { removeCookie } from '@kumix/utils';\n *\n * // Remove simple cookie\n * removeCookie('username');\n *\n * // Remove cookie with specific path\n * removeCookie('auth_token', { path: '/admin' });\n *\n * // Remove cookie with domain\n * removeCookie('session_id', {\n * path: '/',\n * domain: '.example.com'\n * });\n *\n * // Logout function\n * function logout() {\n * removeCookie('auth_token');\n * removeCookie('user_session');\n * removeCookie('csrf_token');\n * redirectToLogin();\n * }\n *\n * // Clear user preferences\n * function resetPreferences() {\n * removeCookie('user_preferences');\n * removeCookie('theme');\n * removeCookie('language');\n * applyDefaultSettings();\n * }\n *\n * // Clear shopping cart\n * function clearCart() {\n * removeCookie('cart_items');\n * removeCookie('cart_total');\n * updateCartDisplay([]);\n * }\n * ```\n */\nexport const removeCookie = (\n name: string,\n options: Pick<CookieOptions, \"path\" | \"domain\"> = {},\n): boolean => {\n if (typeof document === \"undefined\") {\n logger.warn(\"removeCookie: Document is not available (SSR environment)\");\n return false;\n }\n\n try {\n let cookieString = `${encodeURIComponent(name)}=; expires=Thu, 01 Jan 1970 00:00:00 UTC`;\n\n if (options.path) {\n cookieString += `; path=${options.path}`;\n }\n\n if (options.domain) {\n cookieString += `; domain=${options.domain}`;\n }\n\n // biome-ignore lint/suspicious/noDocumentCookie: Legacy cookie API needed for broader browser compatibility\n document.cookie = cookieString;\n\n logger.debug(\"Cookie removed successfully\", { name, options });\n return true;\n } catch (error) {\n logger.error(\"Failed to remove cookie\", { name, error });\n return false;\n }\n};\n\n/**\n * Checks if a cookie exists\n * More efficient than getCookie when you only need to check existence\n *\n * @param name - The name of the cookie to check\n * @returns True if the cookie exists, false otherwise\n *\n * @example\n * ```typescript\n * import { hasCookie } from '@kumix/utils';\n *\n * // Check if user is logged in\n * if (hasCookie('auth_token')) {\n * showDashboard();\n * } else {\n * showLoginForm();\n * }\n *\n * // Check for user preferences\n * if (hasCookie('user_preferences')) {\n * const prefs = getCookie('user_preferences');\n * applyPreferences(prefs);\n * } else {\n * showPreferencesSetup();\n * }\n *\n * // Conditional cookie setting\n * if (!hasCookie('visitor_id')) {\n * setCookie('visitor_id', generateVisitorId(), { expires: 365 });\n * }\n *\n * // Feature flag check\n * const hasFeatureFlag = hasCookie('feature_beta_enabled');\n * if (hasFeatureFlag) {\n * enableBetaFeatures();\n * }\n * ```\n */\nexport const hasCookie = (name: string): boolean => {\n if (typeof document === \"undefined\") {\n logger.warn(\"hasCookie: Document is not available (SSR environment)\");\n return false;\n }\n\n try {\n const nameEQ = `${encodeURIComponent(name)}=`;\n return document.cookie.split(\";\").some((cookie) => {\n return cookie.trim().indexOf(nameEQ) === 0;\n });\n } catch (error) {\n logger.error(\"Failed to check cookie existence\", { name, error });\n return false;\n }\n};\n\n/**\n * Gets all cookies as an object\n * Useful for debugging or bulk operations\n *\n * @returns Object containing all cookies with their parsed values\n *\n * @example\n * ```typescript\n * import { getAllCookies } from '@kumix/utils';\n *\n * // Get all cookies for debugging\n * const allCookies = getAllCookies();\n * console.log('Current cookies:', allCookies);\n *\n * // Check cookie count\n * const cookieCount = Object.keys(getAllCookies()).length;\n * if (cookieCount > 50) {\n * logger.warn('Too many cookies detected', { count: cookieCount });\n * }\n *\n * // Export user data\n * function exportUserData() {\n * const cookies = getAllCookies();\n * const userData = {\n * preferences: cookies.user_preferences,\n * settings: cookies.user_settings,\n * theme: cookies.theme\n * };\n * return userData;\n * }\n *\n * // Cookie audit\n * function auditCookies() {\n * const cookies = getAllCookies();\n * const report = {\n * total: Object.keys(cookies).length,\n * authRelated: Object.keys(cookies).filter(name =>\n * name.includes('auth') || name.includes('session')\n * ).length,\n * preferences: Object.keys(cookies).filter(name =>\n * name.includes('pref') || name.includes('setting')\n * ).length\n * };\n * return report;\n * }\n * ```\n */\nexport const getAllCookies = (): Record<string, unknown> => {\n if (typeof document === \"undefined\") {\n logger.warn(\"getAllCookies: Document is not available (SSR environment)\");\n return {};\n }\n\n try {\n const cookies: Record<string, unknown> = {};\n const cookieArray = document.cookie.split(\";\");\n\n for (let cookie of cookieArray) {\n cookie = cookie.trim();\n const [name, ...valueParts] = cookie.split(\"=\");\n\n if (name && valueParts.length > 0) {\n const value = valueParts.join(\"=\");\n const decodedName = decodeURIComponent(name);\n const decodedValue = decodeURIComponent(value);\n\n try {\n const parsed: CookieValue = JSON.parse(decodedValue);\n cookies[decodedName] = parsed.value;\n } catch {\n // Fallback for cookies not set with our wrapper\n cookies[decodedName] = decodedValue;\n }\n }\n }\n\n logger.debug(\"Retrieved all cookies\", {\n count: Object.keys(cookies).length,\n });\n return cookies;\n } catch (error) {\n logger.error(\"Failed to get all cookies\", { error });\n return {};\n }\n};\n\n/**\n * Clears all cookies for the current domain\n * Useful for logout or reset functionality\n *\n * @param options - Options for path and domain\n * @returns Number of cookies that were attempted to be removed\n *\n * @example\n * ```typescript\n * import { clearAllCookies } from '@kumix/utils';\n *\n * // Clear all cookies\n * const removedCount = clearAllCookies();\n * console.log(`Removed ${removedCount} cookies`);\n *\n * // Clear cookies for specific path\n * clearAllCookies({ path: '/admin' });\n *\n * // Complete logout function\n * function completeLogout() {\n * clearAllCookies();\n * localStorage.clear();\n * sessionStorage.clear();\n * redirectToLogin();\n * }\n *\n * // Reset application state\n * function resetApp() {\n * const cookieCount = clearAllCookies();\n * logger.info('Application reset', { cookiesRemoved: cookieCount });\n * window.location.reload();\n * }\n *\n * // Privacy compliance - clear tracking cookies\n * function clearTrackingCookies() {\n * const allCookies = getAllCookies();\n * const trackingCookies = Object.keys(allCookies).filter(name =>\n * name.includes('_ga') || name.includes('_gid') || name.includes('_fbp')\n * );\n *\n * trackingCookies.forEach(name => removeCookie(name));\n * return trackingCookies.length;\n * }\n * ```\n */\nexport const clearAllCookies = (options: Pick<CookieOptions, \"path\" | \"domain\"> = {}): number => {\n if (typeof document === \"undefined\") {\n logger.warn(\"clearAllCookies: Document is not available (SSR environment)\");\n return 0;\n }\n\n try {\n const cookies = getAllCookies();\n const cookieNames = Object.keys(cookies);\n\n cookieNames.forEach((name) => {\n removeCookie(name, options);\n });\n\n logger.info(\"Cleared all cookies\", {\n count: cookieNames.length,\n options,\n });\n return cookieNames.length;\n } catch (error) {\n logger.error(\"Failed to clear all cookies\", { error });\n return 0;\n }\n};\n","/**\n * Browser element height calculation utilities\n * Provides functions for measuring HTML element dimensions including margins\n */\n\n/**\n * Calculates the total height of an HTML element including its margins\n * This function computes the complete height of an element by combining:\n * - The element's content height (from getBoundingClientRect)\n * - Top margin\n * - Bottom margin\n *\n * This is useful for layout calculations where you need to know the total\n * space an element occupies, including its margins.\n *\n * @param element - The HTML element to measure\n * @returns The total height in pixels including margins, or 0 if element is null/undefined\n *\n * @example\n * ```ts\n * import { getHeight } from '@/utils/functions';\n *\n * // Basic usage\n * const button = document.querySelector('button');\n * const totalHeight = getHeight(button);\n * console.log(`Button takes up ${totalHeight}px of vertical space`);\n *\n * // Use in layout calculations\n * function calculateTotalHeight(elements: HTMLElement[]) {\n * return elements.reduce((total, element) => {\n * return total + getHeight(element);\n * }, 0);\n * }\n *\n * // Dynamic spacing for sticky headers\n * function adjustLayout() {\n * const header = document.querySelector('header') as HTMLElement;\n * const headerHeight = getHeight(header);\n * document.body.style.paddingTop = `${headerHeight}px`;\n * }\n *\n * // Responsive layout adjustments\n * function handleResize() {\n * const sidebar = document.querySelector('.sidebar') as HTMLElement;\n * const sidebarHeight = getHeight(sidebar);\n *\n * if (sidebarHeight > window.innerHeight) {\n * sidebar.style.overflowY = 'scroll';\n * }\n * }\n *\n * // Animation calculations\n * function animateCollapse(element: HTMLElement) {\n * const fullHeight = getHeight(element);\n * element.style.height = `${fullHeight}px`;\n * element.style.transition = 'height 0.3s ease';\n * element.style.height = '0px';\n * }\n * ```\n */\nexport function getHeight(element: HTMLElement): number {\n if (!element) return 0;\n if (typeof window === \"undefined\") return 0;\n\n const styles = window.getComputedStyle(element);\n\n const height = element.getBoundingClientRect().height;\n const marginTop = parseFloat(styles.marginTop);\n const marginBottom = parseFloat(styles.marginBottom);\n\n const totalHeight = height + marginTop + marginBottom;\n\n return totalHeight;\n}\n","/**\n * Utility function for client-side image resizing\n * Provides browser-based image resizing with aspect ratio handling\n */\n\n/**\n * Resizes an image file to specified dimensions while maintaining aspect ratio\n * Uses canvas to perform the resize operation in the browser\n *\n * @param file - The image File object to resize\n * @param opts - Resize options\n * @param opts.width - Target width in pixels (default: 1200)\n * @param opts.height - Target height in pixels (default: 630)\n * @param opts.quality - JPEG quality from 0.0 to 1.0 (default: 1.0)\n * @returns A Promise that resolves to a base64-encoded data URL of the resized image\n *\n * @example\n * ```ts\n * import { resizeImage } from '@/utils/functions';\n *\n * // Basic usage with a file from input\n * const fileInput = document.querySelector('input[type=\"file\"]');\n * fileInput.addEventListener('change', async (e) => {\n * const file = e.target.files[0];\n * if (file) {\n * try {\n * // Resize to default dimensions (1200x630)\n * const resizedImage = await resizeImage(file);\n *\n * // Display the resized image\n * const img = document.createElement('img');\n * img.src = resizedImage;\n * document.body.appendChild(img);\n * } catch (error) {\n * console.error('Image resize failed:', error);\n * }\n * }\n * });\n *\n * // With custom dimensions and quality\n * const thumbnail = await resizeImage(file, {\n * width: 300,\n * height: 200,\n * quality: 0.8\n * });\n *\n * // Use the resized image in an upload\n * const formData = new FormData();\n * formData.append('image', thumbnail);\n * await fetch('/api/upload', { method: 'POST', body: formData });\n * ```\n */\nexport const resizeImage = (\n file: File,\n opts: {\n width: number;\n height: number;\n quality?: number;\n } = {\n width: 1200,\n height: 630,\n quality: 1.0,\n },\n): Promise<string> => {\n if (typeof document === \"undefined\") {\n return Promise.reject(new Error(\"resizeImage only works in browser environments\"));\n }\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = (e: ProgressEvent<FileReader>) => {\n const img = new Image();\n // Attach load/error handlers BEFORE setting src. For cached images the\n // load event can fire synchronously after assigning src, and handlers\n // attached afterwards would miss it, leaving the promise pending forever.\n img.onload = () => {\n const targetWidth = opts.width;\n const targetHeight = opts.height;\n const canvas = document.createElement(\"canvas\");\n canvas.width = targetWidth;\n canvas.height = targetHeight;\n\n const ctx = canvas.getContext(\"2d\") as CanvasRenderingContext2D;\n ctx.imageSmoothingQuality = \"high\"; // Set image smoothing quality to high\n\n // Calculating the aspect ratio\n const sourceWidth = img.width;\n const sourceHeight = img.height;\n const sourceAspectRatio = sourceWidth / sourceHeight;\n const targetAspectRatio = targetWidth / targetHeight;\n\n let drawWidth: number;\n let drawHeight: number;\n let offsetX = 0;\n let offsetY = 0;\n\n // Adjust drawing sizes based on the aspect ratio\n if (sourceAspectRatio > targetAspectRatio) {\n // Source is wider\n drawHeight = sourceHeight;\n drawWidth = sourceHeight * targetAspectRatio;\n offsetX = (sourceWidth - drawWidth) / 2;\n } else {\n // Source is taller or has the same aspect ratio\n drawWidth = sourceWidth;\n drawHeight = sourceWidth / targetAspectRatio;\n offsetY = (sourceHeight - drawHeight) / 2;\n }\n\n // Draw the image onto the canvas\n ctx.drawImage(\n img,\n offsetX,\n offsetY,\n drawWidth,\n drawHeight,\n 0,\n 0,\n targetWidth,\n targetHeight,\n );\n\n // Convert the canvas to a base64 string\n const base64Image = canvas.toDataURL(\"image/jpeg\", opts.quality);\n resolve(base64Image);\n };\n img.onerror = (error) => reject(new Error(`Image loading error: ${error}`));\n img.src = e.target?.result as string;\n };\n reader.onerror = (error) => reject(new Error(`FileReader error: ${error}`));\n reader.readAsDataURL(file);\n });\n};\n\n/**\n * Resize and crop an image to a centered rectangle of the specified size.\n *\n * Processing steps:\n * - Load the image from the given `File`\n * - Determine target width & height from `size`\n * - `number` → width = height = value (e.g. `512`)\n * - `[width, height]` → explicit width & height (e.g. `[512, 1080]`)\n * - `null | undefined` → use the original image width & height\n * - Compute a centered crop region that matches the target aspect ratio\n * - Draw the cropped region to the canvas and export with desired format\n *\n * @param file The source image file to process\n * @param name The base name (without extension) for the output file\n * @param size Target size:\n * - `number` → square (width & height)\n * - `[width, height]` → custom rectangle\n * - `null | undefined` → use original image size\n * @param extension Output image extension (e.g., \"png\", \"jpeg\", \"webp\")\n * @returns A new `File` containing the processed image in the requested format\n *\n * @example\n * ```ts\n * // 1) Square: size = 512 → 512x512\n * const out1 = await resizeAndCropImage(file, \"avatar\", 512, \"webp\");\n *\n * // 2) Custom rectangle: size = [512, 1080] → 512x1080\n * const out2 = await resizeAndCropImage(file, \"poster\", [512, 1080], \"jpeg\");\n *\n * // 3) Keep original dimensions: size = null → originalWidth x originalHeight\n * const out3 = await resizeAndCropImage(file, \"original\", null, \"png\");\n * ```\n */\nexport async function resizeAndCropImage(\n file: File,\n name: string,\n size: number | [number, number] | null | undefined,\n extension: string,\n): Promise<File> {\n const image = await loadImage(file);\n\n // Determine target width & height based on `size` parameter\n let targetWidth: number;\n let targetHeight: number;\n\n if (Array.isArray(size)) {\n [targetWidth, targetHeight] = size;\n } else if (typeof size === \"number\") {\n targetWidth = size;\n targetHeight = size;\n } else {\n // When `size` is null or undefined, use original image dimensions\n targetWidth = image.width;\n targetHeight = image.height;\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = targetWidth;\n canvas.height = targetHeight;\n\n const ctx = canvas.getContext(\"2d\");\n\n // If we are using the original size, just draw the full image without cropping\n if (targetWidth === image.width && targetHeight === image.height) {\n ctx?.drawImage(image, 0, 0);\n } else {\n // Compute centered crop region based on aspect ratio (cover behavior)\n const sourceWidth = image.width;\n const sourceHeight = image.height;\n const sourceAspect = sourceWidth / sourceHeight;\n const targetAspect = targetWidth / targetHeight;\n\n let sx = 0;\n let sy = 0;\n let sWidth = sourceWidth;\n let sHeight = sourceHeight;\n\n if (targetAspect > sourceAspect) {\n // Target is wider → limit by width, crop top & bottom\n sWidth = sourceWidth;\n sHeight = sourceWidth / targetAspect;\n sy = (sourceHeight - sHeight) / 2;\n } else if (targetAspect < sourceAspect) {\n // Target is taller → limit by height, crop left & right\n sHeight = sourceHeight;\n sWidth = sourceHeight * targetAspect;\n sx = (sourceWidth - sWidth) / 2;\n }\n\n ctx?.drawImage(image, sx, sy, sWidth, sHeight, 0, 0, targetWidth, targetHeight);\n }\n\n const resizedImageBlob = await new Promise<Blob | null>((resolve) =>\n canvas.toBlob(resolve, `image/${extension}`),\n );\n\n return new File([resizedImageBlob as BlobPart], `${name}.${extension}`, {\n type: `image/${extension}`,\n });\n}\n\n/**\n * Load a `File` into an `HTMLImageElement` using `FileReader`\n *\n * Behavior:\n * - Reads the file as a Data URL and assigns it to `Image.src`\n * - Resolves once the image has fully loaded\n * - Rejects if the image fails to load\n *\n * @param file The image file to read and load\n * @returns A promise that resolves to an `HTMLImageElement` ready for drawing\n */\nexport async function loadImage(file: File): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const image = new Image();\n const reader = new FileReader();\n\n // Attach image handlers before the data URL is assigned to src to avoid\n // missing the load event on cached/instant-decode images.\n image.onload = () => resolve(image);\n image.onerror = (err) => reject(err);\n\n reader.onload = (e) => {\n image.src = e.target?.result as string;\n };\n\n reader.readAsDataURL(file);\n });\n}\n\n/**\n * Convert a `File` to a Base64-encoded Data URL string\n *\n * @param file The file to convert\n * @returns A promise that resolves to a Base64 Data URL string\n */\nexport async function fileToBase64(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result as string);\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n}\n","/**\n * Browser storage utilities for React applications\n * Provides type-safe localStorage and sessionStorage operations\n * with SSR compatibility and error handling\n */\n\nimport { logger } from \"../logging/logger\";\n\n/**\n * Type representing browser storage options\n * Either localStorage (persists across sessions) or sessionStorage (cleared on tab close)\n */\ntype StorageType = \"localStorage\" | \"sessionStorage\";\n\n/**\n * Gets the appropriate Storage object based on the requested type\n *\n * @param storageType - Which storage type to use\n * @returns The Storage object or null if running in a non-browser environment\n */\nconst getStorageObject = (storageType: StorageType): Storage | null => {\n if (typeof window === \"undefined\") return null;\n return storageType === \"localStorage\" ? localStorage : sessionStorage;\n};\n\n/**\n * Retrieves data from browser storage with type safety\n *\n * @template T - The expected type of the stored data\n * @param key - The storage key to retrieve\n * @param storageType - Which storage to use (defaults to localStorage)\n * @param defaultValue - Value to return if key doesn't exist or on error\n * @returns The parsed data with type T, defaultValue, or undefined\n *\n * @example\n * ```typescript\n * // Get with type safety\n * const user = getStorageItem<User>('user');\n *\n * // With default value\n * const theme = getStorageItem<'light' | 'dark'>('theme', 'localStorage', 'light');\n *\n * // From session storage\n * const tempData = getStorageItem('tempData', 'sessionStorage');\n * ```\n */\nconst getStorageItem = <T = unknown>(\n key: string,\n storageType: StorageType = \"localStorage\",\n defaultValue?: T,\n): T | undefined => {\n try {\n const storage = getStorageObject(storageType);\n if (!storage) return defaultValue;\n\n const data = storage.getItem(key);\n if (data) {\n return JSON.parse(data) as T;\n }\n return defaultValue;\n } catch (error) {\n logger.error(`Read from ${storageType}`, error);\n return defaultValue;\n }\n};\n\n/**\n * Saves data to browser storage\n *\n * @param key - The storage key to set\n * @param value - The value to store (will be JSON stringified)\n * @param storageType - Which storage to use (defaults to localStorage)\n *\n * @example\n * ```typescript\n * // Save to localStorage\n * setStorageItem('user', { id: 1, name: 'John' });\n *\n * // Save to sessionStorage\n * setStorageItem('tempData', data, 'sessionStorage');\n * ```\n */\nconst setStorageItem = (\n key: string,\n value: unknown,\n storageType: StorageType = \"localStorage\",\n): void => {\n try {\n const storage = getStorageObject(storageType);\n if (!storage) return;\n\n storage.setItem(key, JSON.stringify(value));\n } catch (error) {\n logger.error(`Save in ${storageType}`, error);\n }\n};\n\n/**\n * Removes data from browser storage\n *\n * @param key - The storage key to remove\n * @param storageType - Which storage to use (defaults to localStorage)\n *\n * @example\n * ```typescript\n * // Remove from localStorage\n * removeStorageItem('user');\n *\n * // Remove from sessionStorage\n * removeStorageItem('tempData', 'sessionStorage');\n * ```\n */\nconst removeStorageItem = (key: string, storageType: StorageType = \"localStorage\"): void => {\n try {\n const storage = getStorageObject(storageType);\n if (!storage) return;\n\n storage.removeItem(key);\n } catch (error) {\n logger.error(`Remove from ${storageType}`, error);\n }\n};\n\n/**\n * Clears all data from the specified storage\n *\n * @param storageType - Which storage to clear (defaults to localStorage)\n *\n * @example\n * ```typescript\n * // Clear all localStorage\n * clearStorage();\n *\n * // Clear all sessionStorage\n * clearStorage('sessionStorage');\n * ```\n */\nconst clearStorage = (storageType: StorageType = \"localStorage\"): void => {\n try {\n const storage = getStorageObject(storageType);\n if (!storage) return;\n\n storage.clear();\n } catch (error) {\n logger.error(`Clear ${storageType}`, error);\n }\n};\n\n/**\n * Checks if a key exists in browser storage\n *\n * @param key - The storage key to check\n * @param storageType - Which storage to use (defaults to localStorage)\n * @returns Boolean indicating if the key exists\n *\n * @example\n * ```typescript\n * if (hasStorageItem('user')) {\n * // User data exists in localStorage\n * }\n *\n * if (hasStorageItem('session', 'sessionStorage')) {\n * // Session data exists in sessionStorage\n * }\n * ```\n */\nconst hasStorageItem = (key: string, storageType: StorageType = \"localStorage\"): boolean => {\n try {\n const storage = getStorageObject(storageType);\n if (!storage) return false;\n\n return storage.getItem(key) !== null;\n } catch (error) {\n logger.error(`Check ${storageType}`, error);\n return false;\n }\n};\n\nexport {\n clearStorage,\n getStorageItem,\n hasStorageItem,\n removeStorageItem,\n type StorageType,\n setStorageItem,\n};\n","/**\n * Utility functions for generating unique, time-sortable IDs\n * Provides ULID-compatible ID generation with custom prefixes for entity identification\n */\n\nimport baseX from \"base-x\";\n\nconst prefixes = [\n \"acc_\", // account\n \"api_\", // api key\n \"ct_\", // contact\n \"cus_\", // customer\n \"dev_\", // device code\n \"elog_\", // email log\n \"org_\", // organization\n \"invi_\", // invitation\n \"mem_\", // member\n \"pass_\", // passkey\n \"prod_\", // product\n \"proj_\", // project\n \"rt_\", // rate limit\n \"sess_\", // session\n \"subs_\", // subscription\n \"two_\", // two factor auth\n \"user_\", // user\n \"ver_\", // verification token\n \"wh_\", // webhook\n \"ws_\", // workspace\n] as const;\n\n// ULID uses base32 encoding\nconst base32 = baseX(\"0123456789ABCDEFGHJKMNPQRSTVWXYZ\");\n\n/**\n * Creates a ULID-compatible buffer (48 bits timestamp + 80 bits randomness)\n *\n * @returns A 128-bit Uint8Array (6 bytes timestamp + 10 bytes randomness)\n */\nfunction createULIDBuffer(): Uint8Array {\n const buf = new Uint8Array(16); // 128 bits total\n\n // Timestamp (48 bits = 6 bytes)\n const timestamp = BigInt(Date.now());\n buf[0] = Number((timestamp >> BigInt(40)) & BigInt(255));\n buf[1] = Number((timestamp >> BigInt(32)) & BigInt(255));\n buf[2] = Number((timestamp >> BigInt(24)) & BigInt(255));\n buf[3] = Number((timestamp >> BigInt(16)) & BigInt(255));\n buf[4] = Number((timestamp >> BigInt(8)) & BigInt(255));\n buf[5] = Number(timestamp & BigInt(255));\n\n // Randomness (80 bits = 10 bytes)\n globalThis.crypto.getRandomValues(buf.subarray(6));\n\n return buf;\n}\n\n/**\n * Creates a unique, time-sortable ID with a custom prefix\n * Uses ULID format encoded in base32, making the IDs lexicographically sortable\n * by creation time and collision-resistant across distributed systems.\n *\n * @param prefix - Custom string to prepend to the generated ID\n * @returns A unique, time-sortable ID string prefixed with the given value\n *\n * @example\n * ```ts\n * import { baseIdCustom } from '@/utils/functions';\n *\n * // Generate ID with custom prefix\n * const teamId = baseIdCustom({ prefix: 'team_' });\n * // Example output: 'team_01H8XGJWBWBAQ4TPFV5JQ3PYJM'\n *\n * // Use for entities outside the predefined prefix set\n * const invoiceId = baseIdCustom({ prefix: 'inv_' });\n * const apiKey = baseIdCustom({ prefix: 'sk_' });\n * ```\n */\nexport const baseIdCustom = ({ prefix }: { prefix: string }) => {\n const buf = createULIDBuffer();\n const id = base32.encode(buf);\n\n return `${prefix}${id}`;\n};\n\n/**\n * Creates a unique, time-sortable ID with a known prefix from the predefined set\n * Wraps {@link baseIdCustom} with a constrained prefix type to enforce consistency\n * across the application.\n *\n * @param prefix - One of the predefined entity prefixes (e.g. `user_`, `org_`, `sess_`)\n * @returns A unique, time-sortable ID string prefixed with the given value\n *\n * @example\n * ```ts\n * import { baseId } from '@/utils/functions';\n *\n * // Generate IDs for common entity types\n * const userId = baseId({ prefix: 'user_' });\n * // Example output: 'user_01H8XGJWBWBAQ4TPFV5JQ3PYJM'\n *\n * const orgId = baseId({ prefix: 'org_' });\n * const sessionId = baseId({ prefix: 'sess_' });\n *\n * // Use in database models\n * const user = {\n * id: baseId({ prefix: 'user_' }),\n * name: 'John Doe',\n * email: 'john@example.com'\n * };\n * ```\n */\nexport const baseId = ({ prefix }: { prefix: (typeof prefixes)[number] }) =>\n baseIdCustom({ prefix });\n","/**\n * CUID (Collision-resistant Unique IDentifier) generation utilities\n * Provides functions for generating unique identifiers using @paralleldrive/cuid2\n */\n\nimport { createId, init } from \"@paralleldrive/cuid2\";\n\nexport { createId, init as initCuid };\n\n// Cache generators per length so we keep cuid2's internal fingerprint+counter\n// state across calls instead of recreating it on every invocation (which would\n// defeat cuid2's collision-resistance between rapid successive calls).\nconst generatorCache = new Map<number, (prefix?: string) => string>();\n\nfunction getGenerator(length: number): (prefix?: string) => string {\n let generator = generatorCache.get(length);\n if (!generator) {\n // NOTE: do NOT override `random` — cuid2 defaults to a cryptographically\n // secure RNG. Replacing it with Math.random makes IDs predictable.\n generator = init({ length });\n generatorCache.set(length, generator);\n }\n return generator;\n}\n\n/**\n * Generates a CUID (Collision-resistant Unique IDentifier)\n * CUIDs are designed to be globally unique, even in distributed systems.\n * They are based on the current time, a random component, and a counter.\n * Perfect for database IDs, session tokens, and any scenario requiring unique identifiers.\n *\n * @returns A CUID string\n *\n * @example\n * ```ts\n * import { cuid } from '@/utils/functions';\n *\n * // Generate a CUID\n * const id = cuid();\n * // Returns: 'clhqxr8kj0000qzrmn5t8b123'\n *\n * // Use as unique identifiers\n * const userId = cuid();\n * const sessionId = cuid();\n * const transactionId = cuid();\n *\n * // Use in database models\n * const user = {\n * id: cuid(),\n * name: 'John Doe',\n * email: 'john@example.com'\n * };\n *\n * // Use for temporary files\n * const tempFileName = `temp_${cuid()}.json`;\n * ```\n */\nexport function cuid() {\n return createId();\n}\n\n/**\n * Generates a custom ID with an optional prefix and configurable length.\n * Uses `@paralleldrive/cuid2`'s cryptographically-secure RNG.\n *\n * @param prefix - Optional prefix to prepend to the ID\n * @param length - The length of the generated ID (default is 12)\n * @returns A unique custom ID string\n *\n * @example\n * ```ts\n * import { customId } from '@/utils/functions';\n *\n * // Generate ID with prefix\n * const userId = customId('user_');\n * // Returns: 'user_l5r8xn2gzqnb'\n *\n * // Generate ID with custom length\n * const orderId = customId('order_', 16);\n * ```\n */\nexport function customId(prefix?: string, length: number = 12) {\n const generateId = getGenerator(length);\n return `${prefix || \"\"}${generateId()}`;\n}\n\n/**\n * @deprecated Use {@link customId} instead. This alias has a typo and is kept\n * only for backward compatibility; it will be removed in a future major.\n */\nexport const customeId = customId;\n","/**\n * Utility function for cryptographic hashing\n * Provides secure string hashing using the SHA-256 algorithm\n */\n\n/**\n * Hashes a string using the SHA-256 algorithm\n * Uses the Web Crypto API for secure cryptographic operations\n *\n * @param str - The string to hash\n * @returns A Promise that resolves to the hexadecimal representation of the hash\n *\n * @example\n * ```ts\n * import { hashStringSHA256 } from '@/utils/functions';\n *\n * // Basic usage\n * const hash = await hashStringSHA256('hello world');\n * // Returns \"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9\"\n *\n * // For password verification (example only - use proper password hashing in production)\n * async function verifyPassword(inputPassword: string, storedHash: string) {\n * const inputHash = await hashStringSHA256(inputPassword);\n * return inputHash === storedHash;\n * }\n *\n * // For data integrity verification\n * async function verifyDataIntegrity(data: string, expectedHash: string) {\n * const actualHash = await hashStringSHA256(data);\n * return actualHash === expectedHash;\n * }\n * ```\n */\nexport async function hashStringSHA256(str: string): Promise<string> {\n // Encode the string into bytes\n const encoder = new TextEncoder();\n const data = encoder.encode(str);\n\n // Hash the data with SHA-256\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n\n // Convert the buffer to a hexadecimal string\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n\n return hashHex;\n}\n","/**\n * Utility function for generating unique IDs\n * Provides a wrapper around nanoid for consistent ID generation\n */\n\nimport { customAlphabet } from \"nanoid\";\n\nconst DEFAULT_ALPHABET = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\nconst DEFAULT_SIZE = 7;\n\n/**\n * Generates a random alphanumeric ID of specified length\n * Uses a custom alphabet of numbers and letters (both cases)\n *\n * @param chars - The length of the ID to generate (default: 7)\n * @returns A random alphanumeric string of the specified length\n *\n * @example\n * ```ts\n * import { nanoid } from '@/utils/functions';\n *\n * // Generate default 7-character ID\n * const id = nanoid();\n * // Example output: \"a1B2c3D\"\n *\n * // Generate custom length ID\n * const longerId = nanoid(12);\n * // Example output: \"a1B2c3D4e5F6\"\n *\n * // Use as unique identifiers\n * const userId = nanoid();\n * const sessionId = nanoid(10);\n * ```\n */\nexport const nanoid = (chars?: number): string => {\n return customAlphabet(DEFAULT_ALPHABET, chars || DEFAULT_SIZE)();\n};\n\n/**\n * Generates a unique identifier using the current timestamp and a random number\n *\n * This function creates a simple unique ID by combining the current timestamp\n * with a random number. While not cryptographically secure, it's suitable for\n * most UI purposes like generating keys for React components.\n *\n * @returns A string representing the unique ID\n *\n * @example\n * ```typescript\n * // Generate unique IDs for React keys\n * const items = data.map(item => ({\n * ...item,\n * id: uid()\n * }));\n *\n * // Generate unique form field IDs\n * const fieldId = uid();\n * <input id={fieldId} />\n * <label htmlFor={fieldId}>Label</label>\n *\n * // Generate unique component keys\n * {items.map(item => (\n * <Component key={uid()} {...item} />\n * ))}\n * ```\n */\nexport function uid(): string {\n return (Date.now() + Math.floor(Math.random() * 1000)).toString();\n}\n","/**\n * Utility functions for billing date calculations\n * Provides tools for determining billing cycles, adjusting for month lengths, etc.\n */\n\n/**\n * Gets the last day of the current month\n *\n * @param referenceDate - Optional reference date (defaults to current date)\n * @returns The number representing the last day of the month (28-31)\n *\n * @example\n * ```ts\n * // If current month is February 2023\n * getLastDayOfMonth()\n * // Returns 28\n *\n * // If current month is January 2023\n * getLastDayOfMonth()\n * // Returns 31\n *\n * // With specific reference date\n * getLastDayOfMonth(new Date('2023-02-15'))\n * // Returns 28\n * ```\n */\nexport const getLastDayOfMonth = (referenceDate: Date = new Date()): number => {\n const lastDay = new Date(referenceDate.getFullYear(), referenceDate.getMonth() + 1, 0); // This will give the last day of the current month\n return lastDay.getDate();\n};\n\n/**\n * Adjusts the billing cycle start day based on the number of days in the current month\n * Ensures billing cycle start day is valid for months with fewer days\n *\n * @param billingCycleStart - The preferred billing cycle start day (1-31)\n * @param referenceDate - Optional reference date (defaults to current date)\n * @returns An adjusted billing cycle start day that is valid for the current month\n *\n * @example\n * ```ts\n * // If billing cycle starts on the 30th, but current month is February\n * getAdjustedBillingCycleStart(30)\n * // Returns 28 (or 29 in leap years)\n *\n * // If billing cycle starts on the 30th, and current month is January\n * getAdjustedBillingCycleStart(30)\n * // Returns 30 (no adjustment needed)\n *\n * // With specific reference date\n * getAdjustedBillingCycleStart(30, new Date('2023-02-15'))\n * // Returns 28\n * ```\n */\nexport const getAdjustedBillingCycleStart = (\n billingCycleStart: number,\n referenceDate: Date = new Date(),\n): number => {\n const lastDay = getLastDayOfMonth(referenceDate);\n if (billingCycleStart > lastDay) {\n return lastDay;\n } else {\n return billingCycleStart;\n }\n};\n\n/**\n * Calculates the start date of the current billing period\n * Based on the billing cycle start day and the current date\n *\n * @param billingCycleStart - The day of the month when billing cycle starts (1-31)\n * @param referenceDate - Optional reference date (defaults to current date)\n * @returns A Date object representing the start of the current billing period\n *\n * @example\n * ```ts\n * // If today is January 15, 2023 and billing cycle starts on the 10th\n * getBillingStartDate(10)\n * // Returns new Date(\"2023-01-10\") (current month's billing start)\n *\n * // If today is January 5, 2023 and billing cycle starts on the 10th\n * getBillingStartDate(10)\n * // Returns new Date(\"2022-12-10\") (previous month's billing start)\n *\n * // With billing cycle start day that exceeds days in some months (e.g., 31)\n * getBillingStartDate(31, new Date('2023-03-15'))\n * // Returns new Date(\"2023-02-28\") (adjusted for February)\n *\n * // With specific reference date\n * getBillingStartDate(15, new Date('2023-01-20'))\n * // Returns new Date(\"2023-01-15\")\n * ```\n */\nexport const getBillingStartDate = (\n billingCycleStart: number,\n referenceDate: Date = new Date(),\n): Date => {\n const today = referenceDate;\n const currentDay = today.getDate();\n const currentMonth = today.getMonth();\n const currentYear = today.getFullYear();\n const adjustedBillingCycleStart = getAdjustedBillingCycleStart(billingCycleStart, referenceDate);\n if (currentDay <= adjustedBillingCycleStart) {\n // if the current day is less than the billing cycle start, we need to go back a month\n const lastMonth = currentMonth === 0 ? 11 : currentMonth - 1; // if the current month is January, we need to go back to December\n const lastYear = currentMonth === 0 ? currentYear - 1 : currentYear; // if the current month is January, we need to go back a year\n return new Date(lastYear, lastMonth, adjustedBillingCycleStart);\n } else {\n return new Date(currentYear, currentMonth, adjustedBillingCycleStart);\n }\n};\n","/**\n * Utility function for formatting dates in a consistent way\n * Provides human-readable date formatting with customizable options\n */\n\n/**\n * Formats a date into a localized string representation\n *\n * @param datetime - The date to format (can be Date object or string)\n * @param options - Optional Intl.DateTimeFormat options to customize formatting\n * @param locale - Optional locale string (defaults to 'en-US')\n * @returns A formatted date string, or empty string if date is invalid\n *\n * @example\n * ```ts\n * // Basic usage with defaults\n * formatDate(new Date('2023-01-15'))\n * // Returns \"January 15, 2023\"\n *\n * // With a date string\n * formatDate('2023-01-15')\n * // Returns \"January 15, 2023\"\n *\n * // With custom options\n * formatDate(new Date('2023-01-15'), {\n * month: 'short',\n * day: '2-digit'\n * })\n * // Returns \"Jan 15, 2023\"\n *\n * // With custom locale\n * formatDate(new Date('2023-01-15'), undefined, 'de-DE')\n * // Returns \"15. Januar 2023\"\n *\n * // With custom locale and options\n * formatDate(new Date('2023-01-15'), {\n * weekday: 'long',\n * year: 'numeric',\n * month: 'long',\n * day: 'numeric'\n * }, 'fr-FR')\n * // Returns \"dimanche 15 janvier 2023\"\n *\n * // With invalid date\n * formatDate('invalid-date')\n * // Returns \"\"\n * ```\n */\nexport const formatDate = (\n datetime: Date | string,\n options?: Intl.DateTimeFormatOptions,\n locale: string = \"en-US\",\n): string => {\n const date = new Date(datetime);\n if (Number.isNaN(date.getTime())) return \"\";\n return date.toLocaleDateString(locale, {\n day: \"numeric\",\n month: \"long\",\n year: \"numeric\",\n ...options,\n });\n};\n","/**\n * Utility function for smart date and time formatting\n * Provides context-aware datetime formatting based on date proximity to current time\n */\n\n/**\n * Formats a date intelligently - shows year for past years, shows time for current year\n *\n * @param datetime - The date to format (can be Date object or string)\n * @param options - Optional Intl.DateTimeFormat options to customize formatting\n * @param locale - Optional locale string (defaults to 'en-US')\n * @returns A formatted date string with contextual information\n *\n * @example\n * ```ts\n * // For a date in the current year (assuming current year is 2023)\n * formatDateTimeSmart(new Date('2023-06-15'))\n * // Returns \"Jun 15, 10:30 AM\" (with time)\n *\n * // For a date in a previous year\n * formatDateTimeSmart(new Date('2022-06-15'))\n * // Returns \"Jun 15, 2022\" (with year instead of time)\n *\n * // With custom options\n * formatDateTimeSmart(new Date('2022-06-15'), {\n * weekday: 'long'\n * })\n * // Returns \"Wednesday, Jun 15, 2022\"\n *\n * // With custom locale\n * formatDateTimeSmart(new Date('2022-06-15'), undefined, 'fr-FR')\n * // Returns \"15 juin 2022\"\n *\n * // Current year with custom locale\n * formatDateTimeSmart(new Date('2023-06-15'), undefined, 'de-DE')\n * // Returns \"15. Jun, 10:30\" (format depends on locale)\n * ```\n */\nexport const formatDateTimeSmart = (\n datetime: Date | string,\n options?: Intl.DateTimeFormatOptions,\n locale: string = \"en-US\",\n): string => {\n const date = new Date(datetime);\n if (Number.isNaN(date.getTime())) {\n return \"Invalid Date\";\n }\n const now = new Date();\n\n // Use the same timezone basis for the year comparison and the formatting so\n // a date near midnight doesn't compare as a different year than it displays.\n return new Date(datetime).toLocaleDateString(locale, {\n month: \"short\",\n day: \"numeric\",\n ...(date.getFullYear() !== now.getFullYear()\n ? { year: \"numeric\" }\n : {\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n }),\n ...options,\n });\n};\n","/**\n * Utility function for formatting date and time in a consistent way\n * Provides human-readable datetime formatting with customizable options\n */\n\n/**\n * Formats a date and time into a localized string representation\n *\n * @param datetime - The date to format (can be Date object or string)\n * @param options - Optional Intl.DateTimeFormat options to customize formatting\n * @param locale - Optional locale string (defaults to 'en-US')\n * @returns A formatted date and time string, or empty string if date is invalid\n *\n * @example\n * ```ts\n * // Basic usage with defaults\n * formatDateTime(new Date('2023-01-15T14:30:00'))\n * // Returns \"Jan 15, 2023, 2:30 PM\"\n *\n * // With a date string\n * formatDateTime('2023-01-15T14:30:00')\n * // Returns \"Jan 15, 2023, 2:30 PM\"\n *\n * // With custom options\n * formatDateTime(new Date('2023-01-15T14:30:00'), {\n * weekday: 'long',\n * second: 'numeric'\n * })\n * // Returns \"Sunday, Jan 15, 2023, 2:30:00 PM\"\n *\n * // With 24-hour format\n * formatDateTime(new Date('2023-01-15T14:30:00'), {\n * hour12: false\n * })\n * // Returns \"Jan 15, 2023, 14:30\"\n *\n * // With custom locale\n * formatDateTime(new Date('2023-01-15T14:30:00'), undefined, 'de-DE')\n * // Returns \"15. Jan 2023, 14:30\"\n *\n * // With invalid date\n * formatDateTime('invalid-date')\n * // Returns \"\"\n * ```\n */\nexport const formatDateTime = (\n datetime: Date | string,\n options?: Intl.DateTimeFormatOptions,\n locale: string = \"en-US\",\n): string => {\n const date = new Date(datetime);\n if (Number.isNaN(date.getTime())) return \"\";\n return date.toLocaleString(locale, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n ...options,\n });\n};\n","/**\n * Utility function for formatting date periods/ranges\n * Provides consistent date range formatting with smart year display\n */\n\nimport { formatDate } from \"./format-date\";\n\n/**\n * Formats a date period (start and end dates) into a readable range string\n * Shows year only when start and end dates are in different years\n *\n * @param d - Object containing period information\n * @param d.periodStart - Start date of the period\n * @param d.periodEnd - End date of the period\n * @param locale - Optional locale string for date formatting (defaults to 'en-US')\n * @returns A formatted date period string, or '-' if dates are missing\n *\n * @example\n * ```ts\n * // For dates in the same year\n * formatPeriod({\n * periodStart: new Date('2023-01-15'),\n * periodEnd: new Date('2023-06-30')\n * })\n * // Returns \"Jan-Jun\"\n *\n * // For dates in different years\n * formatPeriod({\n * periodStart: new Date('2022-11-01'),\n * periodEnd: new Date('2023-02-28')\n * })\n * // Returns \"Nov 2022-Feb\"\n *\n * // With custom locale\n * formatPeriod({\n * periodStart: new Date('2022-11-01'),\n * periodEnd: new Date('2023-02-28')\n * }, 'fr-FR')\n * // Returns \"nov. 2022-févr.\"\n *\n * // With missing dates\n * formatPeriod({\n * periodStart: null,\n * periodEnd: new Date('2023-02-28')\n * })\n * // Returns \"-\"\n * ```\n */\nexport const formatPeriod = (\n d: {\n periodStart?: Date | null;\n periodEnd?: Date | null;\n },\n locale: string = \"en-US\",\n): string => {\n if (!d.periodStart || !d.periodEnd) {\n return \"-\";\n }\n\n return `${formatDate(\n d.periodStart,\n {\n month: \"short\",\n year:\n new Date(d.periodStart).getUTCFullYear() === new Date(d.periodEnd).getUTCFullYear()\n ? undefined\n : \"numeric\",\n timeZone: \"utc\",\n },\n locale,\n )}-${formatDate(\n d.periodEnd,\n {\n month: \"short\",\n timeZone: \"utc\",\n },\n locale,\n )}`;\n};\n","/**\n * Utility function for formatting time in a consistent way\n * Provides human-readable time formatting with customizable options\n */\n\n/**\n * Formats a time as a readable string in \"Hour:Minute AM/PM\" format\n *\n * Extracts and formats only the time portion from a date object or string.\n * Uses 12-hour format with AM/PM indicators for better readability.\n *\n * @param date - A date object or string to format\n * @param locale - The locale for formatting (defaults to 'en-US')\n * @returns A string formatted as \"Hour:Minute AM/PM\"\n *\n * @example\n * ```typescript\n * // Using default locale\n * formatTime(new Date()); // \"2:30 PM\"\n *\n * // Using specific locale\n * formatTime(new Date(), 'id-ID'); // \"14.30\"\n * formatTime(new Date(), 'de-DE'); // \"14:30\"\n *\n * // With date string\n * formatTime('2023-12-25T14:30:00'); // \"2:30 PM\"\n * ```\n */\nexport const formatTime = (date: Date | string, locale: string = \"en-US\"): string => {\n const parsedDate = typeof date === \"string\" ? new Date(date) : date;\n return new Intl.DateTimeFormat(locale, {\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n }).format(parsedDate);\n};\n","/**\n * Utility function for formatting dates in HTML datetime-local input format\n * Provides consistent datetime string formatting for form inputs\n */\n\n/**\n * Converts a date to a string format compatible with HTML datetime-local inputs\n * Format returned is YYYY-MM-DDThh:mm (compatible with <input type=\"datetime-local\">)\n *\n * @param timestamp - Optional date to format (defaults to current date/time)\n * @returns A string in datetime-local format (YYYY-MM-DDThh:mm), or empty string if date is invalid\n *\n * @example\n * ```ts\n * // Current date/time in datetime-local format\n * getDateTimeLocal()\n * // Returns something like \"2023-06-15T14:30\" (current time)\n *\n * // Specific date in datetime-local format\n * getDateTimeLocal(new Date('2023-06-15T14:30:00'))\n * // Returns \"2023-06-15T14:30\"\n *\n * // With invalid date\n * getDateTimeLocal(new Date('invalid'))\n * // Returns \"\"\n *\n * // Usage with HTML input\n * // <input\n * // type=\"datetime-local\"\n * // value={getDateTimeLocal(startDate)}\n * // onChange={(e) => setStartDate(new Date(e.target.value))}\n * // />\n * ```\n */\nexport const getDateTimeLocal = (timestamp?: Date): string => {\n const d = timestamp ? new Date(timestamp) : new Date();\n if (d.toString() === \"Invalid Date\") return \"\";\n return new Date(d.getTime() - d.getTimezoneOffset() * 60000)\n .toISOString()\n .split(\":\")\n .slice(0, 2)\n .join(\":\");\n};\n","/**\n * Utility function for calculating the difference between dates in days\n * Provides accurate day count calculations for date ranges\n */\n\n/**\n * Calculates the number of days between two dates\n * Returns the absolute difference regardless of which date comes first\n *\n * @param startDate - The first date in the comparison\n * @param endDate - The second date in the comparison\n * @returns The number of days between the two dates (always positive)\n *\n * @example\n * ```ts\n * // Basic usage\n * getDaysDifference(\n * new Date('2023-01-01'),\n * new Date('2023-01-10')\n * )\n * // Returns 9\n *\n * // Order of dates doesn't matter (result is always positive)\n * getDaysDifference(\n * new Date('2023-01-10'),\n * new Date('2023-01-01')\n * )\n * // Returns 9\n *\n * // With time components\n * getDaysDifference(\n * new Date('2023-01-01T10:00:00'),\n * new Date('2023-01-02T08:00:00')\n * )\n * // Returns 1 (rounds up to the nearest day)\n *\n * // Across month boundaries\n * getDaysDifference(\n * new Date('2023-01-28'),\n * new Date('2023-02-05')\n * )\n * // Returns 8\n * ```\n */\nexport const getDaysDifference = (startDate: Date, endDate: Date): number => {\n const diffTime = Math.abs(endDate.getTime() - startDate.getTime());\n return Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n};\n","/**\n * Utility function for calculating billing or subscription periods\n * Provides date range calculations based on a specific day of the month\n */\n\n/**\n * Calculates the first and last day of a period based on a specific day of the month\n * Useful for determining billing cycles, subscription periods, etc.\n *\n * @param day - The day of the month that marks the boundary of the period (1-31)\n * @param referenceDate - Optional reference date (defaults to current date)\n * @returns An object containing the first and last day of the period\n *\n * @example\n * ```ts\n * // If today is May 20, 2023 and the billing day is the 15th\n * getFirstAndLastDay(15)\n * // Returns:\n * // {\n * // firstDay: new Date(\"2023-05-15T00:00:00\"), // May 15, 2023\n * // lastDay: new Date(\"2023-06-14T00:00:00\") // June 14, 2023\n * // }\n *\n * // If today is May 10, 2023 and the billing day is the 15th\n * getFirstAndLastDay(15)\n * // Returns:\n * // {\n * // firstDay: new Date(\"2023-04-15T00:00:00\"), // April 15, 2023\n * // lastDay: new Date(\"2023-05-14T00:00:00\") // May 14, 2023\n * // }\n *\n * // With a specific reference date\n * getFirstAndLastDay(15, new Date('2023-05-20'))\n * // Returns the same result as the first example\n * ```\n */\nexport const getFirstAndLastDay = (\n day: number,\n referenceDate: Date = new Date(),\n): { firstDay: Date; lastDay: Date } => {\n const today = referenceDate;\n const currentDay = today.getDate();\n const currentMonth = today.getMonth();\n const currentYear = today.getFullYear();\n\n // Cap the requested day to the last day of a given (year, month) so that\n // boundary values like 31 don't roll over into the next month\n // (e.g. Feb 31 → Mar 3 in naive `new Date(year, month, day)`).\n const lastDayOfMonth = (year: number, month: number) => new Date(year, month + 1, 0).getDate();\n const clamp = (year: number, month: number, requested: number) =>\n Math.min(requested, lastDayOfMonth(year, month));\n\n if (currentDay >= day) {\n // we just passed `day` earlier this period — current period starts on `day`\n const firstDayClamped = clamp(currentYear, currentMonth, day);\n const lastMonth = currentMonth + 1;\n const lastYear = currentYear + (currentMonth === 11 ? 1 : 0);\n // lastDay = day - 1 of next month, but clamp in case next month is shorter\n const lastDayClamped = clamp(\n lastMonth === 12 ? lastYear : currentYear,\n lastMonth % 12,\n Math.max(1, day - 1),\n );\n return {\n firstDay: new Date(currentYear, currentMonth, firstDayClamped),\n lastDay: new Date(lastMonth === 12 ? lastYear : currentYear, lastMonth % 12, lastDayClamped),\n };\n }\n // we haven't reached `day` yet — current period started in the previous month\n const lastYear = currentMonth === 0 ? currentYear - 1 : currentYear;\n const lastMonth = currentMonth === 0 ? 11 : currentMonth - 1;\n const firstDayClamped = clamp(lastYear, lastMonth, day);\n const lastDayClamped = clamp(currentYear, currentMonth, Math.max(1, day - 1));\n return {\n firstDay: new Date(lastYear, lastMonth, firstDayClamped),\n lastDay: new Date(currentYear, currentMonth, lastDayClamped),\n };\n};\n","/**\n * Year extraction utilities for datetime operations\n * Provides functions for getting current year information\n */\n\n/**\n * Utility function to get the current year as a number\n * Provides a simple way to retrieve the current year from the system date.\n * Commonly used for copyright notices, date ranges, and year-based filtering.\n *\n * @returns The current year as a four-digit number (e.g., 2025)\n *\n * @example\n * ```ts\n * import { getCurrentYear } from '@/utils/functions';\n *\n * // Get the current year\n * const year = getCurrentYear();\n * // Returns: 2025 (if the current year is 2025)\n *\n * // Usage in a copyright footer\n * const Footer = () => (\n * <footer>\n * &copy; {getCurrentYear()} My Company. All rights reserved.\n * </footer>\n * );\n *\n * // Usage in date ranges\n * const yearRange = `2020-${getCurrentYear()}`;\n * // Returns: \"2020-2025\"\n *\n * // Usage in form validation\n * const isValidYear = (inputYear: number) => {\n * const currentYear = getCurrentYear();\n * return inputYear >= 1900 && inputYear <= currentYear;\n * };\n *\n * // Usage in analytics\n * const currentYearData = analytics.filter(item =>\n * item.year === getCurrentYear()\n * );\n * ```\n */\nexport function getCurrentYear(): number {\n return new Date().getFullYear();\n}\n","/**\n * Utility function for displaying relative time in a human-readable format\n * Provides context-aware time formatting based on elapsed time\n */\n\nimport ms from \"ms\";\n\n/**\n * Formats a timestamp into a human-readable relative time string\n *\n * @param timestamp - The date to format (can be Date object or null)\n * @param options - Formatting options\n * @param options.withAgo - Whether to append \"ago\" to the relative time (default: false)\n * @param options.neverText - Text to display for null timestamps (default: \"Never\")\n * @param options.justNowText - Text to display for timestamps less than 1 second ago (default: \"Just now\")\n * @param options.agoText - Text to append for relative times when withAgo is true (default: \"ago\")\n * @param locale - Optional locale string for date formatting (defaults to 'en-US')\n * @returns A formatted relative time string\n *\n * @example\n * ```ts\n * // For recent timestamps (less than 1 second ago)\n * timeAgo(new Date())\n * // Returns \"Just now\"\n *\n * // For timestamps within the last 23 hours\n * timeAgo(new Date(Date.now() - 1000 * 60 * 30))\n * // Returns \"30m\" (30 minutes)\n *\n * // With \"ago\" suffix\n * timeAgo(new Date(Date.now() - 1000 * 60 * 30), { withAgo: true })\n * // Returns \"30m ago\"\n *\n * // For older timestamps (more than 23 hours)\n * timeAgo(new Date(Date.now() - 1000 * 60 * 60 * 24 * 2))\n * // Returns \"Jun 15\" (date format)\n *\n * // For timestamps in previous years\n * timeAgo(new Date('2022-06-15'))\n * // Returns \"Jun 15, 2022\"\n *\n * // With custom locale\n * timeAgo(new Date('2022-06-15'), {}, 'fr-FR')\n * // Returns \"15 juin 2022\"\n *\n * // For null timestamp\n * timeAgo(null)\n * // Returns \"Never\"\n *\n * // With custom text for internationalization\n * timeAgo(null, { neverText: \"Nunca\" })\n * // Returns \"Nunca\"\n *\n * timeAgo(new Date(), { justNowText: \"Ahora mismo\" })\n * // Returns \"Ahora mismo\"\n *\n * timeAgo(new Date(Date.now() - 1000 * 60 * 30), { withAgo: true, agoText: \"atrás\" })\n * // Returns \"30m atrás\"\n *\n * // Full internationalization example\n * timeAgo(new Date(Date.now() - 1000 * 60 * 5), {\n * withAgo: true,\n * justNowText: \"Baru saja\",\n * agoText: \"yang lalu\",\n * neverText: \"Tidak pernah\"\n * }, 'id-ID')\n * // Returns \"5m yang lalu\"\n * ```\n */\nexport const timeAgo = (\n timestamp: Date | null,\n {\n withAgo,\n neverText = \"Never\",\n justNowText = \"Just now\",\n agoText = \"ago\",\n }: {\n withAgo?: boolean;\n neverText?: string;\n justNowText?: string;\n agoText?: string;\n } = {},\n locale: string = \"en-US\",\n): string => {\n if (!timestamp) return neverText;\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 1000) {\n // Less than 1 second in the past, OR a future timestamp within 1s (clock\n // skew) — treat both as \"just now\" so callers don't render \"-5s\" strings.\n return justNowText;\n } else if (diff > 82800000) {\n // more than 23 hours – similar to how Twitter displays timestamps\n return new Date(timestamp).toLocaleDateString(locale, {\n month: \"short\",\n day: \"numeric\",\n year: new Date(timestamp).getFullYear() !== new Date().getFullYear() ? \"numeric\" : undefined,\n });\n }\n return `${ms(diff)}${withAgo ? ` ${agoText}` : \"\"}`;\n};\n","/**\n * Timezone utilities for datetime operations\n * Provides functions for working with timezones and timezone data\n */\n\n/**\n * Retrieves a list of supported time zones with their labels and values\n * This function fetches the available time zones from the environment,\n * formats their offsets (e.g., \"GMT+2\"), and returns them in a sorted array.\n * Useful for timezone selection dropdowns and user preferences.\n *\n * @returns An array of time zone objects with label and value properties, sorted by offset\n *\n * @example\n * ```ts\n * import { getTimeZones } from '@/utils/functions';\n *\n * // Get all available timezones\n * const timezones = getTimeZones();\n * // Returns: [\n * // { label: \"(GMT-12) Etc/GMT+12\", value: \"Etc/GMT+12\" },\n * // { label: \"(GMT-11) Pacific/Midway\", value: \"Pacific/Midway\" },\n * // { label: \"(GMT+0) Europe/London\", value: \"Europe/London\" },\n * // { label: \"(GMT+1) Europe/Paris\", value: \"Europe/Paris\" },\n * // ...\n * // ]\n *\n * // Use in a select dropdown\n * const TimezoneSelect = () => (\n * <select>\n * {getTimeZones().map(tz => (\n * <option key={tz.value} value={tz.value}>\n * {tz.label}\n * </option>\n * ))}\n * </select>\n * );\n *\n * // Find specific timezone\n * const userTimezone = getTimeZones().find(tz =>\n * tz.value === 'America/New_York'\n * );\n * ```\n */\nexport const getTimeZones = (): { label: string; value: string }[] => {\n // `Intl.supportedValuesOf` is unavailable on older engines (e.g. Node <18.14,\n // older Safari). Fall back to a small common list so the helper never throws.\n const safeSupported = (): string[] => {\n if (typeof Intl !== \"undefined\" && typeof Intl.supportedValuesOf === \"function\") {\n try {\n return Intl.supportedValuesOf(\"timeZone\");\n } catch {\n // ignore — fall through\n }\n }\n return [\n \"UTC\",\n \"America/New_York\",\n \"America/Los_Angeles\",\n \"Europe/London\",\n \"Europe/Paris\",\n \"Asia/Tokyo\",\n ];\n };\n\n const timezones = safeSupported();\n\n // Parse a \"GMT[+|-]h(:mm)?\" offset into a numeric value (minutes-from-UTC)\n // so half/quarter-hour zones (e.g. +5:30, +5:45, -3:30) sort correctly.\n // Previously `parseInt(\"5:30\")` returned `5`, tying India with Uzbekistan.\n const parseOffsetMinutes = (offset: string): number => {\n const match = offset.match(/GMT([+-])(\\d{1,2})(?::(\\d{2}))?/);\n if (!match) return 0;\n const sign = match[1] === \"-\" ? -1 : 1;\n const hours = Number.parseInt(match[2] ?? \"0\", 10);\n const minutes = Number.parseInt(match[3] ?? \"0\", 10);\n return sign * (hours * 60 + minutes);\n };\n\n return timezones\n .map((timezone) => {\n const formatter = new Intl.DateTimeFormat(\"en\", {\n timeZone: timezone,\n timeZoneName: \"shortOffset\",\n });\n const parts = formatter.formatToParts(new Date());\n const offset = parts.find((part) => part.type === \"timeZoneName\")?.value || \"\";\n const formattedOffset = offset === \"GMT\" ? \"GMT+0\" : offset;\n\n return {\n value: timezone,\n label: `(${formattedOffset}) ${timezone.replace(/_/g, \" \")}`,\n numericOffset: parseOffsetMinutes(formattedOffset),\n };\n })\n .sort((a, b) => a.numericOffset - b.numericOffset);\n};\n","/**\n * Utility function for formatting file sizes in a human-readable way\n * Converts raw byte values to appropriate size units (KB, MB, GB, etc.)\n */\n\n/**\n * Formats a file size in bytes to a human-readable string with appropriate units\n *\n * @param bytes - File size in bytes\n * @param decimals - Number of decimal places to show (default: 2)\n * @param base - Base for conversion (default: 1024 for binary/IEC, could use 1000 for decimal/SI)\n * @returns A formatted file size string with appropriate unit\n *\n * @example\n * ```ts\n * // Basic usage\n * formatFileSize(1024)\n * // Returns \"1 KB\"\n *\n * // Larger file size\n * formatFileSize(1536)\n * // Returns \"1.5 KB\"\n *\n * // With custom decimal places\n * formatFileSize(1536, 0)\n * // Returns \"2 KB\"\n *\n * // Larger sizes automatically use appropriate units\n * formatFileSize(1048576)\n * // Returns \"1 MB\"\n *\n * // Very large sizes\n * formatFileSize(1073741824)\n * // Returns \"1 GB\"\n *\n * // Using decimal base (1000) instead of binary (1024)\n * formatFileSize(1000000, 2, 1000)\n * // Returns \"1 MB\"\n *\n * // Zero bytes\n * formatFileSize(0)\n * // Returns \"0 Bytes\"\n * ```\n */\nexport function formatFileSize(bytes: number, decimals: number = 2, base: number = 1024): string {\n if (bytes === 0) return \"0 Bytes\";\n if (bytes < 0) return `-${formatFileSize(-bytes, decimals, base)}`;\n\n const k = base;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\n const i = Math.min(Math.floor(Math.log(bytes) / Math.log(k)), sizes.length - 1);\n\n return `${parseFloat((bytes / k ** i).toFixed(decimals))} ${sizes[i]}`;\n}\n","/**\n * Utility function for resilient network requests\n * Provides fetch implementation with timeout, retry, and exponential backoff\n */\n\n/**\n * Performs a fetch request with automatic retries, timeout, and exponential backoff\n * Handles common error scenarios like rate limiting and server errors\n *\n * @param input - The resource URL or Request object to fetch\n * @param init - Optional fetch initialization options\n * @param options - Configuration options for retry behavior\n * @param options.timeout - Maximum time in ms to wait for a response (default: 5000)\n * @param options.maxRetries - Maximum number of retry attempts (default: 10)\n * @param options.retryDelay - Base delay in ms between retries (default: 1000)\n * @returns A Promise that resolves to the fetch Response\n * @throws Error if all retry attempts fail\n *\n * @example\n * ```ts\n * import { fetchWithRetry } from '@/utils/functions';\n *\n * // Basic usage\n * try {\n * const response = await fetchWithRetry('https://api.example.com/data');\n * const data = await response.json();\n * console.log(data);\n * } catch (error) {\n * console.error('Failed to fetch data:', error);\n * }\n *\n * // With custom options\n * const response = await fetchWithRetry('https://api.example.com/data',\n * {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ key: 'value' })\n * },\n * {\n * timeout: 10000, // 10 second timeout\n * maxRetries: 5, // Try 5 times maximum\n * retryDelay: 500 // Start with 500ms delay\n * }\n * );\n *\n * // Handles rate limiting (429) and server errors (5xx) with exponential backoff\n * // Throws error immediately for authentication failures (403)\n * ```\n */\nexport async function fetchWithRetry(\n input: RequestInfo | URL,\n init?: RequestInit | undefined,\n options: {\n timeout?: number;\n maxRetries?: number;\n retryDelay?: number;\n } = {},\n): Promise<Response> {\n const { timeout = 5000, maxRetries = 10, retryDelay = 1000 } = options;\n\n let lastError: Error | null = null;\n let httpError: Error | null = null;\n\n let lastStatus = 0;\n for (let i = 0; i < maxRetries; i++) {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, timeout);\n\n try {\n const response = await fetch(input, {\n ...init,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return response;\n }\n\n lastStatus = response.status;\n\n // Handle rate limiting and server errors (retryable)\n if (response.status === 429 || response.status >= 500) {\n httpError = new Error(`HTTP error ${response.status}`);\n const delay = retryDelay + i ** 2 * 50;\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n\n // Handle unauthorized errors (non-retryable). Both 401 and 403 typically\n // indicate auth problems that retrying won't fix; surface immediately.\n if (response.status === 401 || response.status === 403) {\n httpError = new Error(response.status === 401 ? \"Unauthorized\" : \"Forbidden\");\n break;\n }\n\n // Handle other HTTP errors (non-retryable)\n let errorMessage: string;\n try {\n const error = await response.json();\n errorMessage = error?.error || `HTTP error ${response.status}`;\n } catch {\n errorMessage = `HTTP error ${response.status}`;\n }\n httpError = new Error(errorMessage);\n break;\n } catch (error) {\n clearTimeout(timeoutId);\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // If this is the last retry, throw the error\n if (i === maxRetries - 1) {\n throw new Error(`Failed after ${maxRetries} retries. Last error: ${lastError.message}`);\n }\n\n // For network errors or timeouts, wait and retry\n const delay = retryDelay + i ** 2 * 50;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n // Non-retryable HTTP error from inside the loop\n if (httpError) {\n throw httpError;\n }\n\n // This should never be reached due to the throw in the last retry,\n // but TypeScript needs it for type safety. Surface last seen status.\n throw new Error(\n `Failed after ${maxRetries} retries${lastStatus ? ` (last status: ${lastStatus})` : \"\"}`,\n );\n}\n","/**\n * Utility function for fetch requests with timeout capability\n * Provides a way to abort fetch requests that take too long to complete\n */\n\n/**\n * Performs a fetch request with a specified timeout\n * Automatically aborts the request if it exceeds the timeout duration\n *\n * @param input - The resource URL or Request object to fetch\n * @param init - Optional fetch initialization options\n * @param timeout - Maximum time in ms to wait for a response (default: 5000)\n * @returns A Promise that resolves to the fetch Response or rejects on timeout\n * @throws Error if the request times out or fails\n *\n * @example\n * ```ts\n * import { fetchWithTimeout } from '@/utils/functions';\n *\n * // Basic usage with default timeout (5 seconds)\n * try {\n * const response = await fetchWithTimeout('https://api.example.com/data');\n * const data = await response.json();\n * console.log(data);\n * } catch (error) {\n * console.error('Request failed or timed out:', error);\n * }\n *\n * // With custom timeout (2 seconds)\n * const response = await fetchWithTimeout(\n * 'https://api.example.com/data',\n * {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ key: 'value' })\n * },\n * 2000\n * );\n *\n * // Will throw an error after 2 seconds if the request hasn't completed\n * ```\n */\nexport function fetchWithTimeout(\n input: RequestInfo | URL,\n init?: RequestInit | undefined,\n timeout: number = 5000,\n): Promise<Response> {\n return new Promise<Response>((resolve, reject) => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n reject(new Error(\"Request timed out\"));\n }, timeout);\n fetch(input, { ...init, signal: controller.signal })\n .then((response) => {\n clearTimeout(timeoutId);\n resolve(response);\n })\n .catch((error) => {\n clearTimeout(timeoutId);\n reject(error);\n });\n });\n}\n","/**\n * Utility functions for data fetching\n * Provides enhanced fetch implementation with error handling for SWR\n */\n\nimport { isDevelopment } from \"../../constants/development\";\n\n/**\n * Extended Error interface for SWR compatibility\n * Includes additional properties for error information and HTTP status\n */\ninterface SWRError extends Error {\n info: string | Record<string, unknown>;\n status: number;\n}\n\n/**\n * HTTP request methods supported by the `request` utility\n * Ensures type-safe method selection for fetch operations\n */\ntype RequestMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/**\n * Options for the `request` utility\n * Controls request headers and optional logging\n */\ntype RequestOptions = {\n /**\n * Custom headers to include in the request\n * When sending JSON, `Content-Type: application/json` is automatically added\n */\n headers?: Record<string, string>;\n /**\n * Whether to log the endpoint and response to console\n * Useful for debugging during development (default: false)\n */\n log?: boolean;\n};\n\n/**\n * Fetches data from an API endpoint with proper error handling\n * Designed to work seamlessly with SWR data fetching library\n *\n * @param input - The resource URL or Request object to fetch\n * @param init - Optional fetch initialization options with typed headers\n * @returns A Promise that resolves to the JSON response data\n * @throws SWRError with status code and error information on failure\n *\n * @example\n * ```ts\n * import { fetcher } from '@/utils/functions';\n * import useSWR from 'swr';\n *\n * // Basic usage with SWR\n * const { data, error } = useSWR('/api/user', fetcher);\n *\n * // With custom headers\n * const { data } = useSWR('/api/protected', url =>\n * fetcherSWR(url, {\n * headers: {\n * Authorization: `Bearer ${token}`\n * }\n * })\n * );\n *\n * // Direct usage without SWR\n * try {\n * const data = await fetcherSWR('/api/data');\n * console.log(data);\n * } catch (error) {\n * // Error will include status code and error info\n * console.error(`Error ${error.status}: ${error.info}`);\n * }\n * ```\n */\nexport async function fetcherSWR<T>(\n input: RequestInfo,\n init?: RequestInit & { headers?: Record<string, string> },\n): Promise<T> {\n const res = await fetch(input, {\n ...init,\n ...(init?.headers && { headers: init.headers }),\n });\n\n const data = await res.json();\n\n if (!res.ok) {\n const message = data?.error?.message || \"An error occurred while fetching the data.\";\n const error = new Error(message) as SWRError;\n error.info = message;\n error.status = res.status;\n\n throw error;\n }\n\n return data;\n}\n\n/**\n * Performs an HTTP request with optional JSON or FormData payload\n * Automatically sets `Content-Type: application/json` for JSON bodies\n * Supports basic logging of endpoint and response data\n *\n * @param endpoint - The target URL to send the request to\n * @param method - HTTP method to use (default: `GET`)\n * @param body - Request payload; accepts plain objects or `FormData`\n * @param options - Additional request options like headers and logging\n * @returns A Promise resolving to parsed JSON response\n *\n * @example\n * ```ts\n * // GET request\n * const users = await fetcher('/api/users');\n *\n * // POST JSON body\n * const created = await fetcher('/api/users', 'POST', { name: 'Alice' });\n *\n * // PUT with custom header\n * const updated = await fetcher('/api/users/1', 'PUT', { name: 'Bob' }, {\n * headers: { Authorization: `Bearer ${token}` },\n * });\n *\n * // Multipart/FormData upload\n * const form = new FormData();\n * form.append('file', file);\n * const upload = await fetcher('/api/upload', 'POST', form);\n * ```\n */\nexport async function fetcher<T>(\n endpoint: string,\n method: RequestMethod = \"GET\",\n body?: unknown,\n options?: RequestOptions,\n): Promise<T> {\n const isFormData = typeof FormData !== \"undefined\" && body instanceof FormData;\n\n const headers: Record<string, string> = {\n ...options?.headers,\n };\n\n let payload: BodyInit | undefined;\n\n if (body !== undefined) {\n if (isFormData) {\n payload = body as FormData;\n } else {\n if (!headers[\"Content-Type\"]) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n payload = JSON.stringify(body);\n }\n }\n\n const res = await fetch(endpoint, {\n method,\n headers,\n body: payload,\n });\n\n // Parse the JSON body defensively — non-JSON responses (HTML error pages,\n // empty 204 bodies) would otherwise throw an opaque SyntaxError.\n let data: unknown;\n try {\n data = await res.json();\n } catch {\n data = undefined;\n }\n\n if (options?.log && isDevelopment) {\n console.log(`[request] ${endpoint}`, data);\n }\n\n // Treat non-2xx as an error instead of returning `undefined` as data —\n // matches the behavior of `fetcherSWR` and surfaces failures to callers.\n if (!res.ok) {\n const message =\n (typeof data === \"object\" && data !== null && \"error\" in data\n ? String((data as Record<string, unknown>).error)\n : `HTTP error ${res.status}`) || `HTTP error ${res.status}`;\n const error = new Error(message) as Error & { status: number };\n error.status = res.status;\n throw error;\n }\n\n // Unwrap `{ data: ... }` envelopes when present, otherwise return the body as-is.\n return typeof data === \"object\" && data !== null && \"data\" in data\n ? (data as { data: T }).data\n : (data as T);\n}\n","/**\n * API utilities for Next.js applications\n * Provides helper functions for handling API requests, extracting client information,\n * and managing request/response data in Next.js API routes and middleware\n */\n\n/**\n * Extracts the client IP address from a Next.js request with comprehensive fallback logic\n *\n * This function attempts to get the real client IP address by checking multiple headers\n * in order of preference. It handles various proxy configurations and CDN setups.\n *\n * Header priority:\n * 1. x-forwarded-for (most common, supports proxy chains)\n * 2. x-real-ip (nginx proxy)\n * 3. x-client-ip (Apache proxy)\n * 4. cf-connecting-ip (Cloudflare)\n * 5. x-cluster-client-ip (cluster environments)\n * 6. forwarded (RFC 7239 standard)\n * 7. request.ip (Next.js fallback)\n *\n * @param request - The Next.js request object\n * @returns The client IP address string, or 'unknown' if not found\n *\n * @example\n * ```typescript\n * // In a Next.js API route\n * import { NextRequest, NextResponse } from 'next/server';\n * import { getClientIP } from '@/lib/api';\n *\n * export async function GET(request: NextRequest) {\n * const clientIP = getClientIP(request);\n * console.log(`Request from IP: ${clientIP}`);\n *\n * return NextResponse.json({\n * message: 'Success',\n * clientIP\n * });\n * }\n *\n * // In middleware\n * import { NextRequest, NextResponse } from 'next/server';\n * import { getClientIP } from '@/lib/api';\n *\n * export function middleware(request: NextRequest) {\n * const clientIP = getClientIP(request);\n *\n * // Log or rate limit based on IP\n * console.log(`Middleware: Request from ${clientIP}`);\n *\n * return NextResponse.next();\n * }\n * ```\n */\nexport function getClientIP(request: {\n headers: { get(name: string): string | null };\n ip?: string;\n}): string {\n // Try x-forwarded-for first (most common, handles proxy chains)\n const xForwardedFor = request.headers.get(\"x-forwarded-for\");\n if (xForwardedFor) {\n // x-forwarded-for can contain multiple IPs, take the first one (original client)\n const ips = xForwardedFor.split(\",\").map((ip) => ip.trim());\n const clientIP = ips[0];\n if (clientIP && clientIP !== \"unknown\") {\n return clientIP;\n }\n }\n\n // Try other common headers\n const headers = [\n \"x-real-ip\", // Nginx proxy\n \"x-client-ip\", // Apache proxy\n \"cf-connecting-ip\", // Cloudflare\n \"x-cluster-client-ip\", // Cluster environments\n ];\n\n for (const header of headers) {\n const ip = request.headers.get(header);\n if (ip && ip !== \"unknown\" && ip.trim() !== \"\") {\n return ip.trim();\n }\n }\n\n // Try RFC 7239 Forwarded header\n const forwarded = request.headers.get(\"forwarded\");\n if (forwarded) {\n const forMatch = forwarded.match(/for=([^;,\\s]+)/i);\n if (forMatch?.[1]) {\n // Remove quotes and brackets if present\n const ip = forMatch[1].replace(/[\"[\\]]/g, \"\");\n if (ip && ip !== \"unknown\") {\n return ip;\n }\n }\n }\n\n // Try Next.js request.ip as fallback\n const requestIP = request.ip;\n if (requestIP && requestIP !== \"unknown\") {\n return requestIP;\n }\n\n // Final fallback\n return \"unknown\";\n}\n\n/**\n * Validates if a string is a valid IP address (IPv4 or IPv6)\n *\n * @param ip - The IP address string to validate\n * @returns True if the IP is valid, false otherwise\n *\n * @example\n * ```typescript\n * const ip = getClientIP(request);\n * if (isValidIP(ip)) {\n * console.log('Valid IP:', ip);\n * } else {\n * console.log('Invalid or unknown IP');\n * }\n * ```\n */\nexport function isValidIP(ip: string): boolean {\n if (!ip || ip === \"unknown\") return false;\n\n // IPv4 regex\n const ipv4Regex =\n /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;\n\n // IPv6 regex (simplified)\n const ipv6Regex = /^(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}$|^::1$|^::$/;\n\n return ipv4Regex.test(ip) || ipv6Regex.test(ip);\n}\n\n/**\n * Gets user agent information from the request\n *\n * @param request - The Next.js request object\n * @returns User agent string or 'unknown' if not found\n *\n * @example\n * ```typescript\n * const userAgent = getUserAgent(request);\n * console.log('User Agent:', userAgent);\n * ```\n */\nexport function getUserAgent(request: { headers: { get(name: string): string | null } }): string {\n return request.headers.get(\"user-agent\") || \"unknown\";\n}\n\n/**\n * Gets the request origin/referer information\n *\n * @param request - The Next.js request object\n * @returns Origin information object\n *\n * @example\n * ```typescript\n * const origin = getRequestOrigin(request);\n * console.log('Origin:', origin.origin);\n * console.log('Referer:', origin.referer);\n * ```\n */\nexport function getRequestOrigin(request: { headers: { get(name: string): string | null } }): {\n origin: string;\n referer: string;\n host: string;\n} {\n return {\n origin: request.headers.get(\"origin\") || \"unknown\",\n referer: request.headers.get(\"referer\") || \"unknown\",\n host: request.headers.get(\"host\") || \"unknown\",\n };\n}\n\n/**\n * Extracts the client IP address from a generic headers object (Node.js, Express, etc)\n *\n * This function is similar to getClientIP, but works with any headers object.\n *\n * @param headers - An object containing HTTP headers (key: string, value: string | string[] | undefined)\n * @returns The client IP address string, or 'unknown' if not found\n *\n * @example\n * ```typescript\n * // In Express.js\n * app.use((req, res, next) => {\n * const clientIP = getClientIPFromHeaders(req.headers);\n * console.log('Request from IP:', clientIP);\n * next();\n * });\n * ```\n */\nexport function getClientIPFromHeaders(\n headers: Record<string, string | string[] | undefined>,\n): string {\n // Helper to get header value (case-insensitive)\n const getHeader = (name: string): string | undefined => {\n const value = headers[name] ?? headers[name.toLowerCase()];\n if (Array.isArray(value)) return value[0];\n return value;\n };\n\n // Try x-forwarded-for first (most common, handles proxy chains)\n const xForwardedFor = getHeader(\"x-forwarded-for\");\n if (xForwardedFor) {\n const ips = xForwardedFor.split(\",\").map((ip) => ip.trim());\n const clientIP = ips[0];\n if (clientIP && clientIP !== \"unknown\") {\n return clientIP;\n }\n }\n\n // Try other common headers\n const headerNames = [\"x-real-ip\", \"x-client-ip\", \"cf-connecting-ip\", \"x-cluster-client-ip\"];\n for (const header of headerNames) {\n const ip = getHeader(header);\n if (ip && ip !== \"unknown\" && ip.trim() !== \"\") {\n return ip.trim();\n }\n }\n\n // Try RFC 7239 Forwarded header\n const forwarded = getHeader(\"forwarded\");\n if (forwarded) {\n const forMatch = forwarded.match(/for=([^;,\"]+)/i);\n if (forMatch?.[1]) {\n const ipClean = forMatch[1].replace(/[\"[\\]]/g, \"\");\n if (ipClean && ipClean !== \"unknown\") {\n return ipClean;\n }\n }\n }\n\n // Final fallback\n return \"unknown\";\n}\n\n/**\n * Gets user agent information from a generic headers object (Node.js, Express, etc)\n *\n * @param headers - An object containing HTTP headers (key: string, value: string | string[] | undefined)\n * @returns User agent string or 'unknown' if not found\n *\n * @example\n * ```typescript\n * // In Express.js\n * app.use((req, res, next) => {\n * const userAgent = getUserAgentFromHeaders(req.headers);\n * console.log('User Agent:', userAgent);\n * next();\n * });\n * ```\n */\nexport function getUserAgentFromHeaders(\n headers: Record<string, string | string[] | undefined>,\n): string {\n const value = headers[\"user-agent\"] ?? headers[\"User-Agent\"];\n if (Array.isArray(value)) return value[0] || \"unknown\";\n return value || \"unknown\";\n}\n\n/**\n * Get the client's public IP address using external services.\n *\n * This utility is intended for client-side usage only (it checks for `window`).\n * It attempts multiple providers for resiliency and normalizes the response\n * to a simple string. If all providers fail or the environment is not a\n * browser, it resolves to `'unknown'`.\n *\n * Providers queried (in order):\n * - `https://api.ipify.org?format=json`\n * - `https://ipapi.co/json/`\n * - `https://api.ip.sb/jsonip`\n *\n * @returns Promise that resolves to an IP address string or `'unknown'` if not available\n *\n * @example\n * ```ts\n * import { getIPAddress } from \"@kumix/ui/utils/ip\";\n *\n * const ip = await getIPAddress();\n * // e.g., \"203.0.113.42\" or \"unknown\"\n *\n * // Example in a React component\n * // useEffect(() => {\n * // getIPAddress().then(setIp);\n * // }, []);\n * ```\n */\nexport async function getIPAddress(): Promise<string> {\n if (typeof window === \"undefined\") {\n return \"unknown\";\n }\n\n try {\n // Try multiple IP detection services for reliability\n const services = [\n \"https://api.ipify.org?format=json\",\n \"https://ipapi.co/json/\",\n \"https://api.ip.sb/jsonip\",\n ];\n\n for (const service of services) {\n try {\n const response = await fetch(service, {\n method: \"GET\",\n headers: {\n Accept: \"application/json\",\n },\n });\n\n if (response.ok) {\n const data = await response.json();\n // Different services return IP in different fields\n const ip = data.ip || data.query || data.ipAddress;\n if (ip && typeof ip === \"string\") {\n return ip;\n }\n }\n } catch (serviceError) {\n // Continue to next service if this one fails\n console.warn(`IP service ${service} failed:`, serviceError);\n }\n }\n\n return \"unknown\";\n } catch (error) {\n console.error(\"Failed to get client IP:\", error);\n return \"unknown\";\n }\n}\n","/**\n * Normalize a pathname string.\n *\n * - Ensures it always starts with '/'\n * - Collapses multiple slashes (e.g., `'//a///b'` becomes `'/a/b'`)\n * - Removes trailing slash except for root path (e.g., `'/login/'` becomes `'/login'`)\n *\n * @param input - Any path-like string\n * @returns A normalized path beginning with '/'\n *\n * @example\n * ```ts\n * import { normalizePath } from \"@kumix/ui/utils/parse\";\n *\n * normalizePath(\"dashboard\"); // \"/dashboard\"\n * normalizePath(\"//a///b\"); // \"/a/b\"\n * normalizePath(\"/login/\"); // \"/login\"\n * normalizePath(\"\"); // \"/\"\n * ```\n */\nexport function normalizePath(input: string): string {\n if (!input) return \"/\";\n let p = input.trim();\n if (!p.startsWith(\"/\")) p = `/${p}`;\n p = p.replace(/\\/{2,}/g, \"/\");\n if (p.length > 1 && p.endsWith(\"/\")) p = p.slice(0, -1);\n return p;\n}\n\n/**\n * Interface for parsed request data\n */\nexport interface ParsedRequest {\n /** Normalized domain name (lowercase, without www) */\n domain: string;\n /** URL pathname (e.g., '/dashboard/users') */\n path: string;\n /** Full path including query parameters (e.g., '/dashboard/users?page=1') */\n fullPath: string;\n /** First path segment (e.g., 'dashboard' from '/dashboard/users') */\n key: string;\n /** Full path without leading slash (e.g., 'dashboard/users') */\n fullKey: string;\n /** Query parameters as object */\n searchParamsObj: Record<string, string>;\n /** Query parameters as string (e.g., '?page=1&limit=10') */\n searchParamsString: string;\n}\n\n/**\n * Parse and normalize a Next.js `NextRequest`.\n *\n * Extracts domain, normalized path, first segment key, full path, and\n * query parameters (both as object and as string). Handles international\n * characters via `decodeURIComponent` and normalizes the host by removing\n * a leading `www.`.\n *\n * @param req - The incoming Next.js `NextRequest`\n * @returns Parsed request data with normalized components\n *\n * @example\n * ```ts\n * import type { NextRequest } from \"next/server\";\n * import { parse } from \"@kumix/ui/utils/parse\";\n *\n * export function middleware(req: NextRequest) {\n * const { domain, path, fullPath, key } = parse(req);\n *\n * console.log(domain); // e.g., \"api.kumix.io\"\n * console.log(path); // e.g., \"/v1/users\"\n * console.log(fullPath); // e.g., \"/v1/users?page=1\"\n * console.log(key); // e.g., \"v1\"\n * }\n * ```\n *\n * @example\n * ```ts\n * // Handling international URLs\n * const { key, fullKey } = parse(req);\n * console.log(key); // Decoded first path segment\n * console.log(fullKey); // Decoded full path\n * ```\n *\n * @example\n * ```ts\n * // Working with query parameters\n * const { searchParamsObj, searchParamsString } = parse(req);\n * // searchParamsObj -> { page: \"1\", limit: \"10\" }\n * // searchParamsString -> \"?page=1&limit=10\"\n * ```\n */\nexport const parse =\n // biome-ignore lint/suspicious/noExplicitAny: disable\n (req: any): ParsedRequest => {\n // Extract and normalize domain\n const rawHost = req.headers.get(\"host\");\n const domain = (rawHost || \"\").replace(/^www\\./, \"\").toLowerCase();\n\n // Extract pathname from URL (e.g., kumix.io/stats/github -> /stats/github)\n const path = req.nextUrl.pathname;\n\n // Extract and process search parameters\n const searchParams = req.nextUrl.searchParams.toString();\n const searchParamsObj = Object.fromEntries(req.nextUrl.searchParams);\n const searchParamsString = searchParams.length > 0 ? `?${searchParams}` : \"\";\n\n // Construct full path including query parameters\n const fullPath = `${path}${searchParamsString}`;\n\n // Extract path components with proper URL decoding.\n // This handles international characters (Hebrew, Arabic, Chinese, etc.).\n // `decodeURIComponent` throws URIError on malformed sequences (e.g. stray\n // `%`); fall back to the raw segment so a bad URL never crashes the request.\n const safeDecode = (value: string): string => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n };\n const pathSegments = path.split(\"/\").filter(Boolean);\n const key = pathSegments.length > 0 ? safeDecode(pathSegments[0]) : \"\";\n const fullKey = path.length > 1 ? safeDecode(path.slice(1)) : \"\";\n\n return {\n domain,\n path,\n fullPath,\n key,\n fullKey,\n searchParamsObj,\n searchParamsString,\n };\n };\n","/**\n * Google reCAPTCHA server-side verification utilities\n * Provides secure token verification for reCAPTCHA v2 and v3\n * Integrates with Google's verification API for bot protection\n */\n\nimport { RECAPTCHA_SECRET_KEY } from \"../../constants/env\";\nimport { logger } from \"../logging/logger\";\n\n/**\n * Response interface from Google reCAPTCHA verification API\n * Defines the structure of the response from Google's verification endpoint\n *\n * @property success - Whether the verification was successful\n * @property challenge_ts - Timestamp of the challenge (ISO format)\n * @property hostname - Hostname of the site where the challenge was solved\n * @property error-codes - Array of error codes if verification failed\n */\ninterface ReCaptchaVerifyResponse {\n success: boolean;\n challenge_ts?: string;\n hostname?: string;\n \"error-codes\"?: string[];\n}\n\n/**\n * Verifies a reCAPTCHA token with Google's verification API\n *\n * This function sends the token and secret key to Google's reCAPTCHA\n * verification endpoint and returns whether the verification was successful.\n *\n * @param token - The reCAPTCHA token from the client-side\n * @returns Promise resolving to a boolean indicating verification success\n *\n * @example\n * ```typescript\n * // In a server action or API route\n * const isValid = await verifyRecaptchaToken(token);\n *\n * if (!isValid) {\n * throw new Error('reCAPTCHA verification failed');\n * }\n * ```\n */\nexport async function verifyRecaptchaToken(token: string): Promise<boolean> {\n try {\n const secretKey = RECAPTCHA_SECRET_KEY;\n\n if (!secretKey) {\n logger.error(\"RECAPTCHA_SECRET_KEY is not set\");\n return false;\n }\n\n const response = await fetch(\"https://www.google.com/recaptcha/api/siteverify\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: `secret=${encodeURIComponent(secretKey)}&response=${encodeURIComponent(token)}`,\n });\n\n const data: ReCaptchaVerifyResponse = await response.json();\n\n if (!data.success) {\n logger.error(\"reCAPTCHA verification failed:\", data[\"error-codes\"]);\n return false;\n }\n\n return true;\n } catch (error) {\n logger.error(\"Error verifying reCAPTCHA token:\", error);\n return false;\n }\n}\n","/**\n * Utility functions for logging\n * Provides structured logging to Slack channels based on message type\n */\n\nimport { isDevelopment } from \"../../constants/development\";\nimport { SLACK_WEBHOOKS } from \"../../constants/env\";\nimport { logger } from \"./logger\";\n\n/**\n * Mapping of log types to their corresponding Slack webhook environment variables\n * Each log type is sent to a different Slack channel\n */\nconst logTypeToEnv = {\n alerts: SLACK_WEBHOOKS.ALERTS,\n cron: SLACK_WEBHOOKS.CRON,\n links: SLACK_WEBHOOKS.LINKS,\n subscribers: SLACK_WEBHOOKS.SUBSCRIBERS,\n errors: SLACK_WEBHOOKS.ERRORS,\n};\n\n/**\n * Logs a message to Slack and/or console\n * Sends structured messages to different Slack channels based on message type\n *\n * @param options - Logging options\n * @param options.message - The message to log\n * @param options.type - The type of log determining which Slack channel to use\n * @param options.mention - Whether to mention a specific user in Slack (default: false)\n * @returns A Promise that resolves to the fetch response or undefined\n *\n * @example\n * ```ts\n * import { log } from '@/utils/functions';\n *\n * // Log an error\n * await log({\n * message: \"Database connection failed\",\n * type: \"errors\"\n * });\n *\n * // Log with a mention\n * await log({\n * message: \"Critical system failure\",\n * type: \"alerts\",\n * mention: true\n * });\n *\n * // Log subscriber activity\n * await log({\n * message: \"New subscriber: user@example.com\",\n * type: \"subscribers\"\n * });\n *\n * // In development, logs to console instead of Slack\n * ```\n */\nexport const SlackLog = async ({\n message,\n type,\n mention = false,\n mentionUserId,\n}: {\n message: string;\n type: \"alerts\" | \"cron\" | \"links\" | \"subscribers\" | \"errors\";\n /**\n * Mention a Slack user when `true`. Requires `mentionUserId` to be provided\n * (defaults to env `SLACK_MENTION_USER_ID`) — previously a hardcoded user ID\n * was baked into this published package.\n */\n mention?: boolean;\n /** Slack user ID (e.g. `U0404G6J3NJ`) to mention. Falls back to env. */\n mentionUserId?: string;\n}) => {\n const HOOK = logTypeToEnv[type];\n\n // In development or when the relevant webhook is missing, log to console and bail\n if (isDevelopment || !HOOK) {\n logger.log(message);\n return;\n }\n\n const resolvedMentionId =\n mentionUserId ||\n (typeof process !== \"undefined\" ? process.env.SLACK_MENTION_USER_ID : undefined);\n\n try {\n return await fetch(HOOK, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n blocks: [\n {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n // prettier-ignore\n text: `${mention && resolvedMentionId ? `<@${resolvedMentionId}> ` : \"\"}${type === \"alerts\" || type === \"errors\" ? \":alert: \" : \"\"}${message}`,\n },\n },\n ],\n }),\n });\n } catch (error) {\n logger.log(`Failed to log to Slack. Error: ${error}`);\n }\n};\n","/**\n * Performance debouncing utilities\n * Provides functions for delaying function execution until after a specified delay\n */\n\n/**\n * Debounces a function to delay its execution until after a specified delay\n * Debouncing delays the execution of a function until after a specified time\n * has passed since the last time it was invoked. This is useful for scenarios\n * like search input where you want to wait for the user to stop typing.\n *\n * @param func - The function to debounce\n * @param wait - The delay in milliseconds\n * @returns A debounced version of the provided function\n *\n * @example\n * ```ts\n * import { debounce } from '@/utils/functions';\n *\n * // Debounce search input\n * const debouncedSearch = debounce((query: string) => {\n * performSearch(query);\n * }, 500);\n *\n * // Use in input handler\n * const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {\n * debouncedSearch(e.target.value);\n * };\n *\n * // Debounce window resize\n * const debouncedResize = debounce(() => {\n * handleWindowResize();\n * recalculateLayout();\n * }, 250);\n *\n * window.addEventListener('resize', debouncedResize);\n *\n * // Debounce form validation\n * const debouncedValidate = debounce((formData: FormData) => {\n * validateForm(formData);\n * }, 300);\n *\n * // Debounce auto-save\n * const debouncedSave = debounce(() => {\n * saveDocument();\n * }, 2000);\n * ```\n */\nexport function debounce<T extends (...args: never[]) => unknown>(\n func: T,\n wait: number,\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n\n return (...args: Parameters<T>): void => {\n if (timeout) {\n clearTimeout(timeout);\n }\n\n timeout = setTimeout(() => {\n func(...args);\n }, wait);\n };\n}\n","/**\n * Performance throttling utilities\n * Provides functions for limiting function execution frequency to improve performance\n */\n\n/**\n * Throttles a function to limit its execution to once every specified duration\n * Throttling ensures that a function is called at most once in a specified time period.\n * This is useful for performance optimization, especially for events that fire frequently\n * like scroll, resize, or mousemove events.\n *\n * @param func - The function to throttle\n * @param limit - The minimum delay in milliseconds between calls\n * @returns A throttled version of the provided function\n *\n * @example\n * ```ts\n * import { throttle } from '@/utils/functions';\n *\n * // Throttle scroll event handler\n * const handleScroll = throttle(() => {\n * console.log('Scroll event fired');\n * updateScrollPosition();\n * }, 100);\n *\n * window.addEventListener('scroll', handleScroll);\n *\n * // Throttle API calls\n * const throttledSearch = throttle((query: string) => {\n * searchAPI(query);\n * }, 300);\n *\n * // Throttle resize handler\n * const handleResize = throttle(() => {\n * console.log('Window resized');\n * recalculateLayout();\n * }, 250);\n *\n * window.addEventListener('resize', handleResize);\n *\n * // Throttle button clicks\n * const throttledSubmit = throttle(() => {\n * submitForm();\n * }, 1000);\n * ```\n */\nexport const throttle = <T extends (...args: never[]) => unknown>(\n func: T,\n limit: number,\n): ((...args: Parameters<T>) => void) => {\n let lastFunc: ReturnType<typeof setTimeout> | null = null;\n let lastRan: number | null = null;\n\n return function (this: unknown, ...args: Parameters<T>) {\n if (lastRan === null) {\n func.apply(this, args);\n lastRan = Date.now();\n } else {\n if (lastFunc !== null) {\n clearTimeout(lastFunc);\n }\n lastFunc = setTimeout(\n () => {\n if (Date.now() - (lastRan as number) >= limit) {\n func.apply(this, args);\n lastRan = Date.now();\n }\n },\n limit - (Date.now() - (lastRan as number)),\n );\n }\n };\n};\n","/**\n * Get avatar size class name\n * @param size - Avatar size ('sm', 'lg', or null/undefined for default)\n * @returns Tailwind CSS class name for avatar size\n */\nexport function getSizeAvatar(size: string | null | undefined) {\n return size === \"sm\" ? \"size-6\" : size === \"lg\" ? \"size-10\" : \"size-8\";\n}\n\n/**\n * Get user name from user object\n * @param user - User object\n * @returns User name\n */\nexport function getUserName(\n // biome-ignore lint/suspicious/noExplicitAny: <>\n user: any | null | undefined,\n) {\n return user?.name || user?.displayUsername || user?.username || user?.email;\n}\n","/**\n * Utility function for string case conversion\n * Provides conversion from various cases (snake, kebab, space, Pascal) to camelCase\n */\n\n/**\n * Converts a string to camelCase.\n * Handles snake_case, kebab-case, CONST_CASE, PascalCase, and space-separated words.\n *\n * @param str - The string to convert to camelCase\n * @returns The camelCase version of the input string\n *\n * @example\n * ```ts\n * toCamelCase('user_name') // \"userName\"\n * toCamelCase('user-name') // \"userName\"\n * toCamelCase('first name') // \"firstName\"\n * toCamelCase('PascalCase') // \"pascalCase\"\n * toCamelCase('first_name_last') // \"firstNameLastName\"\n * ```\n */\nexport const toCamelCase = (str: string): string => {\n if (!str) return \"\";\n // Split on any non-alphanumeric boundary (underscore, dash, space) OR at the\n // transition between lowercase/digit and uppercase (PascalCase boundaries).\n const words = str\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean);\n if (words.length === 0) return \"\";\n const [first, ...rest] = words;\n return `${first.toLowerCase()}${rest\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join(\"\")}`;\n};\n","/**\n * Utility function for string capitalization\n * Provides consistent text formatting for display purposes\n */\n\n/**\n * Capitalizes the first character of each word in a string\n * Handles null or undefined values by returning them unchanged\n *\n * @param str - The string to capitalize (can be undefined or null)\n * @returns The capitalized string, or the original value if not a string\n *\n * @example\n * ```ts\n * // Basic usage\n * capitalize('hello world')\n * // Returns \"Hello World\"\n *\n * // Single word\n * capitalize('javascript')\n * // Returns \"Javascript\"\n *\n * // Already capitalized text remains unchanged\n * capitalize('Hello World')\n * // Returns \"Hello World\"\n *\n * // Handles null or undefined\n * capitalize(null)\n * // Returns null\n *\n * capitalize(undefined)\n * // Returns undefined\n *\n * // Mixed case\n * capitalize('javaScript is COOL')\n * // Returns \"Javascript Is COOL\"\n * ```\n */\nexport function capitalize(str?: string | null): string | undefined | null {\n if (!str || typeof str !== \"string\") return str;\n return str\n .split(\" \")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n","/**\n * Utility functions for CSS class name management\n * Provides optimized class name merging with Tailwind CSS conflict resolution\n * Essential for component styling and conditional class application\n */\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merges Tailwind class names, resolving any conflicts.\n * This utility combines clsx for conditional classes with tailwind-merge\n * to properly handle Tailwind CSS class conflicts.\n *\n * @param inputs - An array of class names, objects, or arrays to merge\n * @returns A string of merged and optimized class names\n *\n * @example\n * ```tsx\n * // Basic usage\n * <div className={cn(\"px-4 py-2\", \"bg-blue-500\", \"text-white\")}>\n * Button\n * </div>\n *\n * // With conditional classes\n * <div className={cn(\n * \"px-4 py-2\",\n * isActive && \"bg-blue-500\",\n * !isActive && \"bg-gray-200\",\n * isDisabled && \"opacity-50 cursor-not-allowed\"\n * )}>\n * Button\n * </div>\n *\n * // Resolving conflicts (last one wins)\n * <div className={cn(\"px-2\", \"px-4\")}>\n * // Results in \"px-4\", not \"px-2 px-4\"\n * </div>\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Utility function for combining words into a grammatically correct list\n * Provides natural language formatting for arrays of words\n */\n\n/**\n * Combines an array of words into a grammatically correct list\n * Joins words with commas and adds \"and\" before the last word\n *\n * @param words - Array of words to combine\n * @returns A string with words combined in a natural language format\n *\n * @example\n * ```ts\n * import { combineWords } from '@/utils/functions';\n *\n * // Basic usage\n * combineWords(['apple', 'banana', 'orange'])\n * // Returns \"apple, banana and orange\"\n *\n * // With two words\n * combineWords(['apple', 'banana'])\n * // Returns \"apple and banana\"\n *\n * // With one word\n * combineWords(['apple'])\n * // Returns \"apple\"\n *\n * // With empty array\n * combineWords([])\n * // Returns \"\"\n * ```\n */\nexport const combineWords = (words: string[]): string => {\n return (\n words\n .join(\", \")\n // final one should be \"and\" instead of comma\n .replace(/, ([^,]*)$/, \" and $1\")\n );\n};\n","/**\n * Utility function for formatting numbers as currency\n * Provides consistent currency formatting with customizable options\n */\n\n/**\n * Formats a number as a currency string using Intl.NumberFormat\n *\n * @param value - The numeric value to format as currency\n * @param options - Optional Intl.NumberFormat options to customize formatting\n * @param locale - Optional locale string (defaults to 'en-US')\n * @param currencyCode - Optional currency code (defaults to 'USD')\n * @returns A formatted currency string\n *\n * @example\n * ```ts\n * // Basic usage with defaults (USD)\n * currencyFormatter(1000)\n * // Returns \"$1,000.00\"\n *\n * // With custom currency\n * currencyFormatter(1000, {}, 'en-US', 'EUR')\n * // Returns \"€1,000.00\"\n *\n * // With custom locale\n * currencyFormatter(1000, {}, 'de-DE', 'EUR')\n * // Returns \"1.000,00 €\"\n *\n * // With custom options (no decimals)\n * currencyFormatter(1234.56, { maximumFractionDigits: 0 })\n * // Returns \"$1,235\"\n *\n * // Combining custom options, locale and currency\n * currencyFormatter(1234.56, { maximumFractionDigits: 0 }, 'ja-JP', 'JPY')\n * // Returns \"¥1,235\"\n * ```\n */\nexport const currencyFormatter = (\n value: number,\n options?: Intl.NumberFormatOptions,\n locale: string = \"en-US\",\n currencyCode: string = \"USD\",\n): string =>\n Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: currencyCode,\n ...options,\n }).format(value);\n","/**\n * String initials extraction utilities\n * Provides functions for extracting initials from names for avatars and displays\n */\n\n/**\n * Extracts initials from a given name with customizable count\n * Takes a full name and extracts the first letter of each word to create initials.\n * Useful for avatar placeholders, user displays, and profile components.\n *\n * @param name - The full name to extract initials from\n * @param count - The number of initials to return (defaults to all initials)\n * @returns A string of initials from the name\n *\n * @example\n * ```ts\n * import { getInitials } from '@/utils/functions';\n *\n * // Basic usage\n * const initials1 = getInitials('John Doe');\n * // Returns: 'JD'\n *\n * const initials2 = getInitials('John Michael Doe');\n * // Returns: 'JMD'\n *\n * // Limit number of initials\n * const initials3 = getInitials('John Michael Doe', 2);\n * // Returns: 'JM'\n *\n * const initials4 = getInitials('John Doe', 1);\n * // Returns: 'J'\n *\n * // Handle edge cases\n * const empty1 = getInitials('');\n * // Returns: ''\n *\n * const empty2 = getInitials(null);\n * // Returns: ''\n *\n * const single = getInitials('John');\n * // Returns: 'J'\n *\n * // Use in avatar component\n * const Avatar = ({ name }: { name: string }) => (\n * <div className=\"avatar\">\n * {getInitials(name, 2)}\n * </div>\n * );\n * ```\n */\nexport const getInitials = (name: string | null | undefined, count?: number): string => {\n if (!name || typeof name !== \"string\") {\n return \"\";\n }\n\n const initials = name\n .split(\" \")\n .filter(Boolean)\n .map((part) => part[0].toUpperCase());\n\n return count && count > 0 ? initials.slice(0, count).join(\"\") : initials.join(\"\");\n};\n","/**\n * Utility function for formatting numbers with abbreviations\n * Provides human-readable number formatting for large values\n */\n\n/**\n * Formats a number with abbreviations (K, M, G, T, etc.) or as a full number\n *\n * @param num - The number to format\n * @param opts - Formatting options\n * @param opts.digits - Number of decimal places to show (default: 1)\n * @param opts.full - Whether to show the full number without abbreviation (default: false)\n * @param locale - Optional locale string for full number formatting (defaults to 'en-US')\n * @returns A formatted number string\n *\n * @example\n * ```ts\n * // Basic usage\n * nFormatter(1500)\n * // Returns \"1.5K\"\n *\n * // With custom decimal places\n * nFormatter(1500, { digits: 2 })\n * // Returns \"1.50K\"\n *\n * // Full number formatting\n * nFormatter(1500, { full: true })\n * // Returns \"1,500\"\n *\n * // Small numbers\n * nFormatter(0.75, { digits: 2 })\n * // Returns \"0.75\"\n *\n * // Large numbers with abbreviations\n * nFormatter(1500000)\n * // Returns \"1.5M\"\n *\n * // With custom locale\n * nFormatter(1500000, { full: true }, 'de-DE')\n * // Returns \"1.500.000\"\n *\n * // Zero or undefined\n * nFormatter(0)\n * // Returns \"0\"\n * nFormatter(undefined)\n * // Returns \"0\"\n * ```\n */\nexport function nFormatter(\n num?: number,\n opts: { digits?: number; full?: boolean } = {\n digits: 1,\n },\n locale: string = \"en-US\",\n): string {\n if (!num) return \"0\";\n if (opts.full) {\n return Intl.NumberFormat(locale).format(num);\n }\n\n const rx = /\\.0+$|(\\.[0-9]*[1-9])0+$/;\n const digits = opts.digits ?? 1;\n\n // Handle negative magnitudes by formatting the absolute value and re-applying\n // the sign. Previously negatives with |num| >= 1000 collapsed to \"0\" because\n // the lookup never matched (every value in `lookup` is positive).\n const sign = num < 0 ? \"-\" : \"\";\n const abs = Math.abs(num);\n\n if (abs < 1) {\n return `${sign}${abs.toFixed(digits).replace(rx, \"$1\")}`;\n }\n\n const lookup = [\n { value: 1, symbol: \"\" },\n { value: 1e3, symbol: \"K\" },\n { value: 1e6, symbol: \"M\" },\n { value: 1e9, symbol: \"G\" },\n { value: 1e12, symbol: \"T\" },\n { value: 1e15, symbol: \"P\" },\n { value: 1e18, symbol: \"E\" },\n ];\n const item = lookup\n .slice()\n .reverse()\n .find((item) => abs >= item.value);\n return item\n ? `${sign}${(abs / item.value).toFixed(digits).replace(rx, \"$1\")}${item.symbol}`\n : \"0\";\n}\n","/**\n * Utility function for string normalization\n * Provides consistent string formatting by removing special characters and normalizing whitespace\n */\n\nimport { isDevelopment } from \"../../constants/development\";\nimport { logger } from \"../logging/logger\";\n\n/**\n * Normalizes a string by removing special characters and normalizing whitespace\n * Useful for cleaning user input, keys, and other string data\n *\n * @param key - The string to normalize\n * @returns A normalized string with special characters removed and whitespace normalized\n *\n * @example\n * ```ts\n * import { normalizeString } from '@/utils/functions';\n *\n * // Remove special characters\n * normalizeString('Hello\\u0000World')\n * // Returns \"Hello World\"\n *\n * // Normalize whitespace\n * normalizeString('Hello World')\n * // Returns \"hello world\"\n *\n * // Handle empty input\n * normalizeString('')\n * // Returns \"\"\n *\n * // Normalize case\n * normalizeString('HeLLo WoRLd')\n * // Returns \"hello world\"\n *\n * // Remove BOM and other special characters\n * normalizeString('\\uFEFFHello')\n * // Returns \"hello\"\n * ```\n */\nexport const normalizeString = (key: string): string => {\n if (!key) return \"\";\n\n const original = key;\n const normalized = key\n // Strip a leading UTF-8 BOM expressed either as the actual U+FEFF character\n // or as its raw byte sequence EF BB BF. (\\u escapes only take 4 hex digits,\n // so the previous \\uEFBBBF never matched the bytes.)\n .replace(/^\\uFEFF/, \"\")\n .replace(/^\\uFFFE/, \"\")\n .replace(/^[\\u00EF\\u00BB\\u00BF]+/, \"\")\n // biome-ignore lint/suspicious/noControlCharactersInRegex: handle null-byte + BOM prefixes\n .replace(/^[\\u0000\\uFEFF]{2}/, \"\")\n // biome-ignore lint/suspicious/noControlCharactersInRegex: handle null-byte + noncharacter BOM prefixes\n .replace(/^[\\uFFFE\\u0000]{2}/, \"\")\n .replace(/^\\u2028/, \"\")\n .replace(/^\\u2029/, \"\")\n // Remove any non-printable characters using a function instead of regex with control characters\n .replace(/./g, (char) => {\n const code = char.charCodeAt(0);\n return code <= 0x1f || (code >= 0x7f && code <= 0x9f) ? \"\" : char;\n })\n // Normalize whitespace\n .replace(/\\s+/g, \" \")\n .trim()\n // Optional: normalize case\n .toLowerCase();\n\n // Logging is gated behind an explicit env var (KUMIX_DEBUG_NORMALIZE) to avoid\n // accidentally dumping user input / secrets through the logger in dev.\n if (isDevelopment && process.env.KUMIX_DEBUG_NORMALIZE && original !== normalized) {\n logger.log(\n `normalizeString: input changed (length ${original.length} -> ${normalized.length})`,\n );\n }\n\n return normalized;\n};\n","/**\n * Utility function for pluralizing words\n * Provides simple English pluralization based on count\n */\n\n/**\n * Pluralizes a word based on a count value\n * Returns singular form for count=1, plural form otherwise\n *\n * @param word - The word to pluralize\n * @param count - The count determining whether to use singular or plural form\n * @param options - Optional configuration\n * @param options.plural - Custom plural form (if not provided, 's' is appended)\n * @returns The appropriate singular or plural form based on count\n *\n * @example\n * ```ts\n * import { pluralize } from '@/utils/functions';\n *\n * // Basic usage\n * pluralize('item', 1)\n * // Returns \"item\"\n *\n * pluralize('item', 2)\n * // Returns \"items\"\n *\n * // With custom plural form\n * pluralize('category', 1)\n * // Returns \"category\"\n *\n * pluralize('category', 2, { plural: 'categories' })\n * // Returns \"categories\"\n *\n * // In a sentence\n * const count = 5;\n * `You have ${count} ${pluralize('message', count)}`\n * // Returns \"You have 5 messages\"\n * ```\n */\nexport const pluralize = (\n word: string,\n count: number,\n options: {\n plural?: string;\n } = {},\n) => {\n if (count === 1) {\n return word;\n }\n\n // Use custom plural form if provided, otherwise add 's'\n return options.plural || `${word}s`;\n};\n","/**\n * Utility function for regular expression handling\n * Provides safe string escaping for use in regular expressions\n */\n\n/**\n * Escapes special characters in a string for use in a regular expression\n * Ensures that special regex characters are treated as literals\n * Based on: https://stackoverflow.com/a/6969486\n *\n * @param str - The string to escape for regex use\n * @returns A string with all regex special characters escaped\n *\n * @example\n * ```ts\n * import { regexEscape } from '@/utils/functions';\n *\n * // Basic usage\n * regexEscape('hello.world')\n * // Returns \"hello\\.world\"\n *\n * // Escaping special characters\n * regexEscape('(test)[123]+?')\n * // Returns \"\\(test\\)\\[123\\]\\+\\?\"\n *\n * // Creating a safe regex from user input\n * const userInput = 'user.input+';\n * const safeRegex = new RegExp(regexEscape(userInput));\n * // Creates a regex that matches the literal string \"user.input+\"\n *\n * // Using in string replacement\n * const text = \"Hello (world)\";\n * const searchTerm = \"(world)\";\n * text.replace(new RegExp(regexEscape(searchTerm)), \"everyone\");\n * // Returns \"Hello everyone\"\n * ```\n */\nexport function regexEscape(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","/**\n * Utility function for string truncation\n * Provides a simple way to limit string length with ellipsis\n */\n\n/**\n * Truncates a string to a specified length and adds ellipsis\n * Handles null and undefined values gracefully\n *\n * @param str - The string to truncate\n * @param length - Maximum length of the truncated string (including ellipsis)\n * @returns Truncated string with ellipsis, or null if input is null/undefined\n *\n * @example\n * ```ts\n * import { truncate } from '@/utils/functions';\n *\n * // Basic usage\n * truncate('This is a long string that needs truncation', 20)\n * // Returns \"This is a long st...\"\n *\n * // String shorter than max length (no truncation)\n * truncate('Short string', 20)\n * // Returns \"Short string\"\n *\n * // With null input\n * truncate(null, 10)\n * // Returns null\n *\n * // With undefined input\n * truncate(undefined, 10)\n * // Returns null\n *\n * // Display truncated text in UI\n * const displayTitle = (title: string) => {\n * return truncate(title, 50) || 'Untitled';\n * };\n * ```\n */\nexport const truncate = (str: string | null | undefined, length: number): string | null => {\n if (!str) return null;\n if (str.length <= length) return str;\n // Ellipsis needs at least 4 chars to fit (\"x...\"); for smaller lengths, fall\n // back to a hard slice so the result never exceeds the requested length.\n const ELLIPSIS = \"...\";\n if (length <= ELLIPSIS.length) {\n return str.slice(0, length);\n }\n return `${str.slice(0, length - ELLIPSIS.length)}${ELLIPSIS}`;\n};\n","/**\n * Utility functions for smart URL truncation\n * Provides intelligent truncation that preserves important parts of URLs\n */\n\nimport { truncate } from \"./truncate\";\n\n/**\n * Truncates a domain name while preserving the TLD\n * Ensures the domain remains recognizable even when shortened\n *\n * @param domain - The domain name to truncate\n * @param maxLength - Maximum length for the truncated domain\n * @returns A truncated domain with preserved TLD\n *\n * @example\n * truncateDomain('verylongdomain.com', 10)\n * // Returns \"verylong...com\"\n */\nconst truncateDomain = (domain: string, maxLength: number): string => {\n const parts = domain.split(\".\");\n const tld = parts.pop() || \"\";\n const rest = parts.join(\".\");\n\n return `${rest.slice(0, maxLength)}...${tld}`;\n};\n\n/**\n * Intelligently truncates a URL while preserving important parts\n * Dynamically adjusts based on the length of the domain and path,\n * giving priority to the path and truncating the domain if necessary,\n * while ensuring the domain still shows at least 8 characters\n *\n * @param link - The URL or path to truncate\n * @param maxLength - Maximum length for the truncated result\n * @returns A smartly truncated URL that preserves important parts\n *\n * @example\n * ```ts\n * import { smartTruncate } from '@/utils/functions';\n *\n * // Basic usage\n * smartTruncate('example.com/very/long/path/to/resource', 25)\n * // Returns \"exam...com/very/long/path/to\"\n *\n * // Short URL (no truncation needed)\n * smartTruncate('example.com/path', 25)\n * // Returns \"example.com/path\"\n *\n * // Very long domain with short path\n * smartTruncate('verylongdomainname.com/path', 25)\n * // Returns \"verylong...com/path\"\n *\n * // Very long path with short domain\n * smartTruncate('short.com/very/long/path/to/resource', 25)\n * // Returns \"short.com/very/long/path/to\"\n * ```\n */\nexport const smartTruncate = (link: string, maxLength: number): string => {\n if (!link) return \"\";\n if (maxLength <= 0) return \"\";\n if (link.length <= maxLength) return link;\n\n const [domain, ...pathParts] = link.split(\"/\");\n const path = pathParts.join(\"/\");\n const minDomainLength = 8;\n\n // If the requested length can't even fit the minimum domain reservation,\n // bail out with a hard slice of the whole string. Going below zero would\n // otherwise feed `truncate` a negative length and slice from the end.\n if (maxLength < minDomainLength) {\n return link.slice(0, maxLength);\n }\n\n // calculate max path length\n const maxPathLength = maxLength - minDomainLength;\n\n // Truncate path. `truncate` returns null for falsy input, so handle the\n // \"no path\" case explicitly to avoid emitting `${domain}/null`.\n const truncatedPath = path ? truncate(path, maxPathLength) : null;\n if (!truncatedPath) {\n return truncateDomain(domain, maxLength);\n }\n\n // Truncate domain if necessary, preserving TLD\n const truncatedDomain = truncateDomain(domain, maxLength - truncatedPath.length);\n\n return `${truncatedDomain}/${truncatedPath}`;\n};\n","/**\n * Utility function for safe string trimming\n * Provides type-safe trimming that handles non-string inputs gracefully\n */\n\n/**\n * Safely trims a string value, returning non-string values unchanged\n * Useful for processing user input or data from external sources\n *\n * @param u - The value to trim, can be any type\n * @returns The trimmed string if input is a string, otherwise the original value\n *\n * @example\n * ```ts\n * import { trim } from '@/utils/functions';\n *\n * // With string input\n * trim(' hello world ')\n * // Returns \"hello world\"\n *\n * // With non-string input\n * trim(123)\n * // Returns 123 (unchanged)\n *\n * trim(null)\n * // Returns null (unchanged)\n *\n * // Useful for processing form data\n * const processFormData = (data: Record<string, unknown>) => {\n * return Object.fromEntries(\n * Object.entries(data).map(([key, value]) => [key, trim(value)])\n * );\n * };\n * ```\n */\nexport const trim = (u: unknown): unknown => (typeof u === \"string\" ? u.trim() : u);\n","/**\n * URL validation utilities\n * Provides functions for validating URL strings and checking URL validity\n */\n\n/**\n * Checks if a string is a valid URL.\n *\n * By default rejects non-fetchable schemes (`javascript:`, `data:`, `file:`,\n * `vbscript:`) to avoid XSS via redirect/href validation. Set `allowAnyScheme`\n * to accept any scheme the URL parser accepts.\n *\n * Uses the URL constructor for validation.\n *\n * @param url - The string to check\n * @param options - Validation options\n * @param options.allowAnyScheme - When true, accept any scheme (defaults to false)\n * @returns True if the string is a valid URL, false otherwise\n *\n * @example\n * ```typescript\n * import { isValidUrl } from '@kumix/utils';\n *\n * // Valid URLs\n * isValidUrl('https://example.com'); // true\n * isValidUrl('http://localhost:3000'); // true\n * isValidUrl('ftp://files.example.com'); // true\n *\n * // Invalid / unsafe URLs (rejected by default)\n * isValidUrl('javascript:alert(1)'); // false\n * isValidUrl('example.com'); // false (missing protocol)\n *\n * // Use in form validation\n * function validateUrlInput(input: string) {\n * if (!isValidUrl(input)) {\n * return 'Please enter a valid URL';\n * }\n * return null;\n * }\n * ```\n */\nexport const isValidUrl = (url: string, options: { allowAnyScheme?: boolean } = {}): boolean => {\n if (!url || typeof url !== \"string\") return false;\n try {\n const parsed = new URL(url);\n if (options.allowAnyScheme) return true;\n // Block schemes that are unsafe when fed back into href/redirect targets.\n const blocked = [\"javascript:\", \"data:\", \"vbscript:\", \"file:\"];\n const scheme = parsed.protocol.toLowerCase();\n if (blocked.some((b) => scheme === b)) {\n return false;\n }\n return true;\n } catch (_) {\n return false;\n }\n};\n","/**\n * Utility functions for domain name operations\n * Provides tools for domain validation, parsing, and generation\n */\n\nimport slugify from \"@sindresorhus/slugify\";\n\nimport { ccTLDs } from \"../../constants/domain/cctlds\";\nimport { SECOND_LEVEL_DOMAINS } from \"../../constants/domain/second\";\nimport { SPECIAL_APEX_DOMAINS } from \"../../constants/domain/special\";\nimport { isValidUrl } from \"./url-validation\";\n\n/**\n * Generates a domain name from a given string\n * Attempts to create a short, memorable domain using various strategies\n *\n * @param name - The name to generate a domain from\n * @param extension - The domain extension to use (default: \"link\")\n * @returns A generated domain name, or empty string if generation fails\n *\n * @example\n * ```ts\n * import { generateDomainFromName } from '@/utils/functions';\n *\n * // Basic usage with default extension (.link)\n * generateDomainFromName('My Cool Project')\n * // Returns \"mycoolproject.link\"\n *\n * // With custom extension\n * generateDomainFromName('My Cool Project', 'com')\n * // Returns \"mycoolproject.com\"\n *\n * // ccTLD fallback only applies when the trailing 2 chars form a known ccTLD;\n * // for \"Canada\" the trailing 2 chars are \"da\" (not a ccTLD), so the default\n * // extension is used.\n * generateDomainFromName('Canada')\n * // Returns \"canada.link\"\n *\n * // With vowels removed if needed\n * generateDomainFromName('Digital', 'io')\n * // Returns \"dgtl.io\"\n * ```\n */\nexport const generateDomainFromName = (name: string, extension: string = \"link\"): string => {\n const normalizedName = slugify(name, { separator: \"\" });\n if (normalizedName.length < 3) {\n return \"\";\n }\n if (ccTLDs.has(normalizedName.slice(-2))) {\n return `${normalizedName.slice(0, -2)}.${normalizedName.slice(-2)}`;\n }\n // remove vowels\n const devowel = normalizedName.replace(/[aeiou]/g, \"\");\n if (devowel.length >= 3 && ccTLDs.has(devowel.slice(-2))) {\n return `${devowel.slice(0, -2)}.${devowel.slice(-2)}`;\n }\n\n const shortestString = [normalizedName, devowel].reduce((a, b) => (a.length < b.length ? a : b));\n\n return `${shortestString}.${extension}`;\n};\n\n/**\n * Regular expression for validating domain names\n * Ensures domains follow standard naming conventions\n *\n * @example\n * ```ts\n * import { validDomainRegex } from '@/utils/functions';\n *\n * // Check if a domain is valid\n * const isValidDomain = (domain: string) => validDomainRegex.test(domain);\n *\n * isValidDomain('example.com') // true\n * isValidDomain('sub.example.co.uk') // true\n * isValidDomain('invalid domain') // false\n * ```\n */\nexport const validDomainRegex = new RegExp(\n /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$/,\n);\n\n/**\n * Regular expression for validating URL slugs\n * Ensures slugs only contain alphanumeric characters and hyphens\n *\n * @example\n * ```ts\n * import { validSlugRegex } from '@/utils/functions';\n *\n * // Check if a slug is valid\n * const isValidSlug = (slug: string) => validSlugRegex.test(slug);\n *\n * isValidSlug('my-page') // true\n * isValidSlug('about123') // true\n * isValidSlug('invalid_slug') // false (contains underscore)\n * ```\n */\nexport const validSlugRegex = new RegExp(/^[a-zA-Z0-9-]+$/);\n\n/**\n * Extracts the subdomain from a full domain name\n *\n * @param name - The full domain name (e.g., \"sub.example.com\")\n * @param apexName - The apex domain (e.g., \"example.com\")\n * @returns The subdomain or null if there is no subdomain\n *\n * @example\n * ```ts\n * import { getSubdomain } from '@/utils/functions';\n *\n * // Get subdomain\n * getSubdomain('app.example.com', 'example.com')\n * // Returns \"app\"\n *\n * // Multiple levels of subdomains\n * getSubdomain('dev.app.example.com', 'example.com')\n * // Returns \"dev.app\"\n *\n * // No subdomain\n * getSubdomain('example.com', 'example.com')\n * // Returns null\n * ```\n */\nexport const getSubdomain = (name: string, apexName: string): string | null => {\n if (name === apexName) return null;\n return name.slice(0, name.length - apexName.length - 1);\n};\n\n/**\n * Extracts the apex (root) domain from a URL\n * Handles special cases like second-level TLDs and website builder domains\n *\n * @param url - The URL to extract the apex domain from\n * @returns The apex domain, or empty string if extraction fails\n *\n * @example\n * ```ts\n * import { getApexDomain } from '@/utils/functions';\n *\n * // Basic usage\n * getApexDomain('https://example.com/page')\n * // Returns \"example.com\"\n *\n * // With subdomain\n * getApexDomain('https://app.example.com')\n * // Returns \"example.com\"\n *\n * // With second-level TLD\n * getApexDomain('https://example.co.uk')\n * // Returns \"example.co.uk\"\n *\n * // With special apex domain\n * getApexDomain('https://myproject.vercel.app')\n * // Returns \"myproject.vercel.app\"\n *\n * // Special case for YouTube\n * getApexDomain('https://youtu.be/12345')\n * // Returns \"youtube.com\"\n * ```\n */\nexport const getApexDomain = (url: string): string => {\n let domain = \"\";\n try {\n // replace any custom scheme (e.g. notion://) with https://\n // use the URL constructor to get the hostname\n domain = new URL(url.replace(/^[a-zA-Z]+:\\/\\//, \"https://\")).hostname;\n } catch (_) {\n return \"\";\n }\n if (domain === \"youtu.be\") return \"youtube.com\";\n\n const parts = domain.split(\".\");\n if (parts.length > 2) {\n if (\n // if this is a second-level TLD (e.g. co.uk, .com.ua, .org.tt), we need to return the last 3 parts\n (SECOND_LEVEL_DOMAINS.has(parts[parts.length - 2]) && ccTLDs.has(parts[parts.length - 1])) ||\n // if it's a special subdomain for website builders (e.g. weathergpt.vercel.app/)\n SPECIAL_APEX_DOMAINS.has(parts.slice(-2).join(\".\"))\n ) {\n return parts.slice(-3).join(\".\");\n }\n // otherwise, it's a subdomain (e.g. kumix.vercel.app), so we return the last 2 parts\n return parts.slice(-2).join(\".\");\n }\n // if it's a normal domain (e.g. kumix.io), we return the domain\n return domain;\n};\n\n/**\n * Removes the \"www.\" prefix from a domain if present\n * Attempts to parse the input as a URL if it's not already a valid URL\n *\n * @param url - The URL or domain to process\n * @returns The domain without \"www.\" prefix, or null if parsing fails\n *\n * @example\n * ```ts\n * import { getDomainWithoutWWW } from '@/utils/functions';\n *\n * // With www prefix\n * getDomainWithoutWWW('https://www.example.com')\n * // Returns \"example.com\"\n *\n * // Without www prefix\n * getDomainWithoutWWW('https://example.com')\n * // Returns \"example.com\"\n *\n * // With just domain (no protocol)\n * getDomainWithoutWWW('www.example.com')\n * // Returns \"example.com\"\n *\n * // Invalid input\n * getDomainWithoutWWW('not a domain')\n * // Returns null\n * ```\n */\nexport const getDomainWithoutWWW = (url: string): string | null | undefined => {\n if (isValidUrl(url)) {\n return new URL(url).hostname.replace(/^www\\./, \"\");\n }\n try {\n if (url.includes(\".\") && !url.includes(\" \")) {\n return new URL(`https://${url}`).hostname.replace(/^www\\./, \"\");\n }\n } catch (_) {\n return null;\n }\n};\n","/**\n * Utility functions for constructing URLs and links\n * Provides tools for building URLs with various options and formats\n */\n\n/**\n * Constructs a URL with various options\n * Handles special cases like root paths and optional search parameters\n *\n * @param options - Configuration options for the URL\n * @param options.domain - The domain name (optional)\n * @param options.key - The path key or slug (optional)\n * @param options.pretty - Whether to remove protocol for display purposes (optional)\n * @param options.searchParams - URL search parameters to include (optional)\n * @returns A formatted URL string, or empty string if no domain is provided\n *\n * @example\n * ```ts\n * import { linkConstructor } from '@/utils/functions';\n *\n * // Basic usage\n * linkConstructor({ domain: 'example.com', key: 'page' })\n * // Returns \"https://example.com/page\"\n *\n * // Root path (no key)\n * linkConstructor({ domain: 'example.com' })\n * // Returns \"https://example.com\"\n *\n * // With special _root key\n * linkConstructor({ domain: 'example.com', key: '_root' })\n * // Returns \"https://example.com\"\n *\n * // With search parameters\n * linkConstructor({\n * domain: 'example.com',\n * key: 'search',\n * searchParams: { q: 'query', page: '1' }\n * })\n * // Returns \"https://example.com/search?q=query&page=1\"\n *\n * // Pretty format (without protocol)\n * linkConstructor({ domain: 'example.com', key: 'about', pretty: true })\n * // Returns \"example.com/about\"\n *\n * // With internationalized domain name\n * linkConstructor({ domain: 'mañana.com', key: 'café' })\n * // Returns \"https://xn--maana-pta.com/xn--caf-dma\" (punycode encoded)\n * ```\n */\nexport function linkConstructor({\n domain,\n key,\n pretty,\n searchParams,\n}: {\n domain?: string;\n key?: string;\n pretty?: boolean;\n searchParams?: Record<string, string>;\n}) {\n if (!domain) {\n return \"\";\n }\n\n let url = `https://${domain}${key && key !== \"_root\" ? `/${key}` : \"\"}`;\n\n if (searchParams) {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(searchParams)) {\n search.set(key, value);\n }\n url += `?${search.toString()}`;\n }\n\n return pretty ? url.replace(/^https?:\\/\\//, \"\") : url;\n}\n\n/**\n * Simplified version of linkConstructor with fewer options\n * Creates a basic URL without extra encoding or search parameters\n *\n * @param options - Configuration options for the URL\n * @param options.domain - The domain name\n * @param options.key - The path key or slug\n * @returns A formatted URL string\n *\n * @example\n * ```ts\n * import { linkConstructorSimple } from '@/utils/functions';\n *\n * // Basic usage\n * linkConstructorSimple({ domain: 'example.com', key: 'page' })\n * // Returns \"https://example.com/page\"\n *\n * // With special _root key\n * linkConstructorSimple({ domain: 'example.com', key: '_root' })\n * // Returns \"https://example.com\"\n * ```\n */\nexport function linkConstructorSimple({ domain, key }: { domain: string; key: string }) {\n return `https://${domain}${key === \"_root\" ? \"\" : `/${key}`}`;\n}\n\n// /**\n// * Returns the base URL of the site based on environment variables.\n// *\n// * @param context - The context of the base URL (main, app, portal, admin)\n// * @returns A string representing the base URL of the site.\n// *\n// * @example\n// * ```ts\n// * const url = baseUrl();\n// * // \"https://example.com\" (from env)\n// * // or \"https://your-vercel-project.vercel.app\"\n// * // or \"http://localhost:3000\"\n// * ```\n// */\n// export function baseUrl(context: 'main' | 'app' | 'portal' | 'admin' = 'main') {\n// const url =\n// context === 'app'\n// ? APP_DOMAIN\n// : context === 'portal'\n// ? PORTAL_DOMAIN\n// : context === 'admin'\n// ? ADMIN_DOMAIN\n// : MAIN_DOMAIN;\n// return url;\n// }\n","/**\n * URL search parameters utilities\n * Provides functions for extracting and manipulating URL search parameters\n */\n\n/**\n * Extracts search parameters from a URL as a simple object\n * Converts URLSearchParams to a plain JavaScript object\n *\n * @param url - The URL to extract search parameters from\n * @returns An object with search parameters as key-value pairs\n *\n * @example\n * ```typescript\n * import { getSearchParams } from '@kumix/utils';\n *\n * // Basic usage\n * getSearchParams('https://example.com?name=John&age=30');\n * // Returns { name: 'John', age: '30' }\n *\n * // With multiple parameters\n * getSearchParams('https://example.com/search?q=test&page=2&limit=10');\n * // Returns { q: 'test', page: '2', limit: '10' }\n *\n * // Note: If the same parameter appears multiple times, only the last value is kept\n * getSearchParams('https://example.com?tag=js&tag=react');\n * // Returns { tag: 'react' }\n *\n * // Use in form initialization\n * const urlParams = getSearchParams(window.location.href);\n * const initialFormData = {\n * search: urlParams.q || '',\n * category: urlParams.category || 'all'\n * };\n *\n * // Use in API calls\n * const params = getSearchParams(requestUrl);\n * const response = await api.search(params);\n * ```\n */\nexport const getSearchParams = (url: string): Record<string, string> => {\n // Create a params object\n const params = {} as Record<string, string>;\n\n // Wrap in try/catch for consistency with getParamsFromURL — a malformed\n // (relative, empty) URL used to throw TypeError and crash the caller.\n try {\n new URL(url).searchParams.forEach((val, key) => {\n params[key] = val;\n });\n } catch {\n // return whatever was collected (empty object on parse failure)\n }\n\n return params;\n};\n\n/**\n * Extracts search parameters from a URL, handling multiple values as arrays\n * Similar to getSearchParams but preserves multiple occurrences of the same parameter\n *\n * @param url - The URL to extract search parameters from\n * @returns An object with search parameters as key-value pairs, with arrays for repeated parameters\n *\n * @example\n * ```typescript\n * import { getSearchParamsWithArray } from '@kumix/utils';\n *\n * // With single parameters\n * getSearchParamsWithArray('https://example.com?name=John&age=30');\n * // Returns { name: 'John', age: '30' }\n *\n * // With repeated parameters\n * getSearchParamsWithArray('https://example.com?tag=js&tag=react&tag=typescript');\n * // Returns { tag: ['js', 'react', 'typescript'] }\n *\n * // Mixed single and repeated parameters\n * getSearchParamsWithArray('https://example.com/search?q=test&filter=name&filter=date');\n * // Returns { q: 'test', filter: ['name', 'date'] }\n *\n * // Use in filtering systems\n * const params = getSearchParamsWithArray(window.location.href);\n * const filters = Array.isArray(params.filter) ? params.filter : [params.filter].filter(Boolean);\n * const results = data.filter(item =>\n * filters.every(filter => item.tags.includes(filter))\n * );\n *\n * // Use in multi-select forms\n * const urlParams = getSearchParamsWithArray(url);\n * const selectedCategories = Array.isArray(urlParams.category)\n * ? urlParams.category\n * : urlParams.category ? [urlParams.category] : [];\n * ```\n */\nexport const getSearchParamsWithArray = (url: string): Record<string, string | string[]> => {\n const params = {} as Record<string, string | string[]>;\n\n try {\n new URL(url).searchParams.forEach((val, key) => {\n if (key in params) {\n const param = params[key];\n if (Array.isArray(param)) {\n param.push(val);\n } else {\n params[key] = [param as string, val];\n }\n } else {\n params[key] = val;\n }\n });\n } catch {\n // return whatever was collected (empty object on parse failure)\n }\n\n return params;\n};\n\n/**\n * Extracts non-empty search parameters from a URL\n * Similar to getSearchParams but filters out empty values\n *\n * @param url - The URL to extract search parameters from\n * @returns An object with non-empty search parameters as key-value pairs\n *\n * @example\n * ```typescript\n * import { getParamsFromURL } from '@kumix/utils';\n *\n * // Basic usage\n * getParamsFromURL('https://example.com?name=John&age=30');\n * // Returns { name: 'John', age: '30' }\n *\n * // With empty parameters (these are filtered out)\n * getParamsFromURL('https://example.com?name=John&empty=&blank=');\n * // Returns { name: 'John' }\n *\n * // With invalid URL\n * getParamsFromURL('not-a-url');\n * // Returns {}\n *\n * // With empty URL\n * getParamsFromURL('');\n * // Returns {}\n *\n * // Use in form validation\n * const params = getParamsFromURL(window.location.href);\n * const hasRequiredParams = 'id' in params && 'token' in params;\n * if (!hasRequiredParams) {\n * throw new Error('Missing required parameters');\n * }\n *\n * // Use in analytics\n * const trackingParams = getParamsFromURL(referrerUrl);\n * if (Object.keys(trackingParams).length > 0) {\n * analytics.track('page_view_with_params', trackingParams);\n * }\n * ```\n */\nexport const getParamsFromURL = (url: string): Record<string, string> => {\n if (!url) return {};\n try {\n const params = new URL(url).searchParams;\n const paramsObj: Record<string, string> = {};\n for (const [key, value] of params.entries()) {\n if (value && value !== \"\") {\n paramsObj[key] = value;\n }\n }\n return paramsObj;\n } catch (_) {\n return {};\n }\n};\n","/**\n * URL conversion utilities\n * Provides functions for converting strings to URLs and creating absolute URLs\n */\n\n// import {\n// ADMIN_DOMAIN,\n// APP_DOMAIN,\n// MAIN_DOMAIN,\n// PORTAL_DOMAIN,\n// } from '../../constants';\nimport { isValidUrl } from \"./url-validation\";\n\n// /**\n// * Constructs an absolute URL based on the base application URL\n// *\n// * Safely combines a base URL with a relative path, handling edge cases\n// * like missing slashes and ensuring proper URL formation.\n// *\n// * @param path - The relative path to append to the base URL\n// * @param context - The context of the base URL (main, app, portal, admin)\n// * @returns A string representing the absolute URL\n// *\n// * @example\n// * ```typescript\n// * import { absoluteUrl } from '@kumix/utils';\n// *\n// * // With environment variable\n// * const profileUrl = absoluteUrl('/profile/123');\n// * // Result: 'https://example.com/profile/123'\n// *\n// * // With explicit base URL\n// * const apiUrl = absoluteUrl('/v1/users');\n// * // Result: 'https://api.example.com/v1/users'\n// *\n// * // Handles missing slashes\n// * const url1 = absoluteUrl('/path'); // 'https://example.com/path'\n// * const url2 = absoluteUrl('path'); // 'https://example.com/path'\n// *\n// * // Use in API calls\n// * const response = await fetch(absoluteUrl('/api/users'));\n// *\n// * // Use in redirects\n// * router.push(absoluteUrl('/dashboard'));\n// * ```\n// */\n// export function absoluteUrl(\n// path: string,\n// context: 'main' | 'app' | 'portal' | 'admin' = 'main',\n// ): string {\n// const url =\n// context === 'app'\n// ? APP_DOMAIN\n// : context === 'portal'\n// ? PORTAL_DOMAIN\n// : context === 'admin'\n// ? ADMIN_DOMAIN\n// : MAIN_DOMAIN;\n// const baseUrl = url + '/';\n\n// if (baseUrl && baseUrl !== '/') {\n// return baseUrl + path;\n// } else {\n// return path;\n// }\n// }\n\n/**\n * Attempts to convert a string to a valid URL\n * If the string is not a valid URL but looks like a domain, prepends https://\n *\n * @param str - The string to convert\n * @returns A valid URL string or the original string if conversion fails\n *\n * @example\n * ```typescript\n * import { getUrlFromString } from '@kumix/utils';\n *\n * // Already valid URL\n * getUrlFromString('https://example.com'); // \"https://example.com\"\n *\n * // Domain without protocol\n * getUrlFromString('example.com'); // \"https://example.com\"\n * getUrlFromString('subdomain.example.com'); // \"https://subdomain.example.com\"\n *\n * // Not a URL\n * getUrlFromString('not a url'); // \"not a url\" (unchanged)\n * getUrlFromString('just text'); // \"just text\" (unchanged)\n *\n * // Use in link processing\n * function processUserInput(input: string) {\n * const url = getUrlFromString(input);\n * if (isValidUrl(url)) {\n * return `<a href=\"${url}\">${input}</a>`;\n * }\n * return input;\n * }\n * ```\n */\nexport const getUrlFromString = (str: string): string => {\n if (isValidUrl(str)) return str;\n try {\n if (str.includes(\".\") && !str.includes(\" \")) {\n return new URL(`https://${str}`).toString();\n }\n } catch (_) {\n // Ignore invalid URLs\n }\n return str;\n};\n\n/**\n * Attempts to convert a string to a URL object\n * If the string is not a valid URL but looks like a domain, prepends https://\n *\n * @param str - The string to convert\n * @returns A URL object or null if conversion fails\n *\n * @example\n * ```typescript\n * import { getUrlObjFromString } from '@kumix/utils';\n *\n * // Already valid URL\n * const url1 = getUrlObjFromString('https://example.com');\n * // Returns URL object for \"https://example.com\"\n *\n * // Domain without protocol\n * const url2 = getUrlObjFromString('example.com');\n * // Returns URL object for \"https://example.com\"\n *\n * // Not a URL\n * const url3 = getUrlObjFromString('not a url');\n * // Returns null\n *\n * // Use for URL manipulation\n * const urlObj = getUrlObjFromString('example.com');\n * if (urlObj) {\n * urlObj.searchParams.set('utm_source', 'newsletter');\n * console.log(urlObj.toString()); // \"https://example.com?utm_source=newsletter\"\n * }\n *\n * // Extract URL components\n * const urlObj = getUrlObjFromString('https://api.example.com/v1/users');\n * if (urlObj) {\n * console.log(urlObj.hostname); // \"api.example.com\"\n * console.log(urlObj.pathname); // \"/v1/users\"\n * }\n * ```\n */\nexport const getUrlObjFromString = (str: string): URL | null => {\n if (isValidUrl(str)) return new URL(str);\n try {\n if (str.includes(\".\") && !str.includes(\" \")) {\n return new URL(`https://${str}`);\n }\n } catch (_) {\n // Ignore invalid URLs\n }\n return null;\n};\n\n/**\n * Attempts to convert a string to a valid URL, returning null if invalid\n * Similar to getUrlFromString but returns null instead of the original string on failure\n *\n * @param str - The string to convert\n * @returns A valid URL string or null if conversion fails\n *\n * @example\n * ```typescript\n * import { getUrlFromStringIfValid } from '@kumix/utils';\n *\n * // Already valid URL\n * getUrlFromStringIfValid('https://example.com'); // \"https://example.com\"\n *\n * // Domain without protocol\n * getUrlFromStringIfValid('example.com'); // \"https://example.com\"\n *\n * // Not a URL\n * getUrlFromStringIfValid('not a url'); // null\n *\n * // Use in conditional logic\n * const userInput = 'example.com';\n * const validUrl = getUrlFromStringIfValid(userInput);\n * if (validUrl) {\n * // Process as valid URL\n * window.open(validUrl, '_blank');\n * } else {\n * // Handle invalid input\n * alert('Please enter a valid URL');\n * }\n *\n * // Filter valid URLs from array\n * const inputs = ['example.com', 'not a url', 'https://test.com'];\n * const validUrls = inputs\n * .map(getUrlFromStringIfValid)\n * .filter(Boolean); // ['https://example.com', 'https://test.com']\n * ```\n */\nexport const getUrlFromStringIfValid = (str: string): string | null => {\n if (isValidUrl(str)) return str;\n try {\n if (str.includes(\".\") && !str.includes(\" \")) {\n return new URL(`https://${str}`).toString();\n }\n } catch (_) {\n // Ignore invalid URLs\n }\n return null;\n};\n","/**\n * URL formatting utilities\n * Provides functions for formatting URLs and generating URL-friendly slugs\n */\n\n/**\n * Formats a URL for display by removing protocol, www prefix, and trailing slash\n * Creates a cleaner, more user-friendly URL representation\n *\n * @param url - The URL to format\n * @returns A formatted URL string without protocol, www prefix, and trailing slash\n *\n * @example\n * ```typescript\n * import { getPrettyUrl } from '@kumix/utils';\n *\n * // Remove protocol and www\n * getPrettyUrl('https://www.example.com');\n * // Returns \"example.com\"\n *\n * // Remove trailing slash\n * getPrettyUrl('https://example.com/');\n * // Returns \"example.com\"\n *\n * // With path\n * getPrettyUrl('https://www.example.com/path/to/page/');\n * // Returns \"example.com/path/to/page\"\n *\n * // With subdomain\n * getPrettyUrl('https://api.example.com/v1');\n * // Returns \"api.example.com/v1\"\n *\n * // With null or undefined\n * getPrettyUrl(null);\n * // Returns \"\"\n *\n * // Use in UI components\n * function LinkDisplay({ url }: { url: string }) {\n * return <span className=\"text-gray-500\">{getPrettyUrl(url)}</span>;\n * }\n *\n * // Use in breadcrumbs\n * const breadcrumb = getPrettyUrl(currentUrl).split('/');\n * ```\n */\nexport const getPrettyUrl = (url?: string | null): string => {\n if (!url) return \"\";\n // remove protocol (http/https) and the leading www. host label only.\n // also remove trailing slash\n return url\n .replace(/(^\\w+:|^)\\/\\//, \"\")\n .replace(/^www\\./, \"\")\n .replace(/\\/$/, \"\");\n};\n\n/**\n * Generates a URL-friendly slug from a given title\n *\n * Converts any string into a clean, URL-safe slug by removing special characters,\n * normalizing unicode, and replacing spaces with hyphens. Perfect for creating\n * SEO-friendly URLs from titles, names, or other text content.\n *\n * @param title - The title to convert into a slug (e.g., \"Write a Proposal\")\n * @returns A slug string (e.g., \"write-a-proposal\")\n *\n * @example\n * ```typescript\n * import { getSlug } from '@kumix/utils';\n *\n * // Basic usage\n * getSlug('Hello World'); // 'hello-world'\n * getSlug('Write a Proposal'); // 'write-a-proposal'\n *\n * // Handles special characters\n * getSlug('Café & Restaurant!'); // 'cafe-restaurant'\n * getSlug('100% Success Rate'); // '100-success-rate'\n *\n * // Handles unicode and diacritics\n * getSlug('Résumé'); // 'resume'\n * getSlug('Naïve Approach'); // 'naive-approach'\n *\n * // Edge cases\n * getSlug(''); // ''\n * getSlug(' '); // ''\n * getSlug('---'); // ''\n * getSlug('Multiple Spaces'); // 'multiple-spaces'\n *\n * // Use in blog post URLs\n * const blogPost = {\n * title: 'How to Build a SaaS Application',\n * slug: getSlug('How to Build a SaaS Application') // 'how-to-build-a-saas-application'\n * };\n *\n * // Use in file naming\n * const fileName = `${getSlug(documentTitle)}.pdf`;\n *\n * // Use in route generation\n * const route = `/blog/${getSlug(post.title)}`;\n * ```\n */\nexport function getSlug(title: string): string {\n // Return empty string for invalid input\n if (!title || typeof title !== \"string\") {\n return \"\";\n }\n\n return title\n .toLowerCase() // Convert to lowercase for consistency\n .trim() // Remove leading/trailing whitespace\n .normalize(\"NFD\") // Normalize unicode (e.g., \"é\" -> \"e\")\n .replace(/[\\u0300-\\u036f]/g, \"\") // Remove diacritics\n .replace(/[^a-z0-9\\s-]/g, \"\") // Remove special characters except spaces/hyphens\n .replaceAll(/\\s+/g, \"-\") // Replace spaces with single hyphen\n .replace(/-+/g, \"-\") // Collapse multiple hyphens\n .replace(/^-|-$/g, \"\"); // Remove leading/trailing hyphens\n}\n","/**\n * UTM parameters utilities\n * Provides functions for handling UTM tracking parameters in URLs\n */\n\n/**\n * Standard UTM parameters and referral tags used in marketing campaigns\n * Provides a type-safe list of recognized UTM parameters\n *\n * @example\n * ```typescript\n * import { UTMTags } from '@kumix/utils';\n *\n * // Use in type definitions\n * type UTMParams = Partial<Record<typeof UTMTags[number], string>>;\n *\n * // Check if a parameter is a valid UTM tag\n * const isValidUTMTag = (tag: string): boolean =>\n * UTMTags.includes(tag as any);\n *\n * // Access specific tags\n * console.log(UTMTags[0]); // 'utm_source'\n *\n * // Generate form fields for UTM parameters\n * const utmFields = UTMTags.map(tag => ({\n * name: tag,\n * label: tag.replace('utm_', 'UTM ').replace(/\\b\\w/g, l => l.toUpperCase())\n * }));\n * ```\n */\nexport const UTMTags = [\n \"utm_source\",\n \"utm_medium\",\n \"utm_campaign\",\n \"utm_term\",\n \"utm_content\",\n \"ref\",\n] as const;\n\n/**\n * Metadata for UTM parameters with display names and examples\n * Provides human-readable information about each UTM parameter\n *\n * @example\n * ```typescript\n * import { paramsMetadata } from '@kumix/utils';\n *\n * // Access parameter metadata\n * const sourceParam = paramsMetadata.find(param => param.key === 'utm_source');\n * console.log(sourceParam);\n * // Returns { display: 'UTM Source', key: 'utm_source', examples: 'google, twitter' }\n *\n * // Generate form fields for UTM parameters\n * const formFields = paramsMetadata.map(param => ({\n * id: param.key,\n * label: param.display,\n * placeholder: `e.g., ${param.examples}`\n * }));\n *\n * // Find a parameter by display name\n * const findParamByDisplay = (display: string) =>\n * paramsMetadata.find(param => param.display === display);\n *\n * // Create help text for users\n * const helpText = paramsMetadata.map(param =>\n * `${param.display}: ${param.examples}`\n * ).join('\\n');\n * ```\n */\nexport const paramsMetadata = [\n { display: \"UTM Source\", key: \"utm_source\", examples: \"google, twitter\" },\n { display: \"UTM Medium\", key: \"utm_medium\", examples: \"social, email\" },\n { display: \"UTM Campaign\", key: \"utm_campaign\", examples: \"summer sale\" },\n { display: \"UTM Term\", key: \"utm_term\", examples: \"blue shoes\" },\n { display: \"UTM Content\", key: \"utm_content\", examples: \"logo link\" },\n { display: \"Referral (ref)\", key: \"ref\", examples: \"google, twitter\" },\n];\n\n/**\n * Constructs a URL with UTM parameters\n * Adds or updates UTM parameters in a URL, handling empty values\n *\n * @param url - The base URL to add UTM parameters to\n * @param utmParams - Object containing UTM parameters as key-value pairs\n * @returns The URL with UTM parameters added, or empty string if URL is invalid\n *\n * @example\n * ```typescript\n * import { constructURLFromUTMParams } from '@kumix/utils';\n *\n * // Add UTM parameters to a URL\n * constructURLFromUTMParams('https://example.com', {\n * utm_source: 'twitter',\n * utm_medium: 'social',\n * utm_campaign: 'summer_sale'\n * });\n * // Returns \"https://example.com?utm_source=twitter&utm_medium=social&utm_campaign=summer_sale\"\n *\n * // Update existing UTM parameters\n * constructURLFromUTMParams('https://example.com?utm_source=google', {\n * utm_source: 'twitter',\n * utm_medium: 'social'\n * });\n * // Returns \"https://example.com?utm_source=twitter&utm_medium=social\"\n *\n * // Remove a UTM parameter by setting it to empty string\n * constructURLFromUTMParams('https://example.com?utm_source=google&utm_medium=cpc', {\n * utm_medium: ''\n * });\n * // Returns \"https://example.com?utm_source=google\"\n *\n * // With invalid URL\n * constructURLFromUTMParams('', { utm_source: 'twitter' });\n * // Returns \"\"\n *\n * // Use in link generation\n * const campaignUrl = constructURLFromUTMParams(baseUrl, {\n * utm_source: 'newsletter',\n * utm_medium: 'email',\n * utm_campaign: 'product_launch'\n * });\n * ```\n */\nexport const constructURLFromUTMParams = (\n url: string,\n utmParams: Record<string, string>,\n): string => {\n if (!url) return \"\";\n try {\n const newURL = new URL(url);\n for (const [key, value] of Object.entries(utmParams)) {\n if (value === \"\") {\n newURL.searchParams.delete(key);\n } else {\n newURL.searchParams.set(key, value.replace(/\\+/g, \" \"));\n }\n }\n return newURL.toString();\n } catch (_) {\n return \"\";\n }\n};\n\n/**\n * Removes all UTM parameters from a URL\n * Useful for cleaning URLs before sharing or storing\n *\n * @param url - The URL to remove UTM parameters from\n * @returns The URL without any UTM parameters\n *\n * @example\n * ```typescript\n * import { getUrlWithoutUTMParams } from '@kumix/utils';\n *\n * // Remove UTM parameters\n * getUrlWithoutUTMParams('https://example.com?utm_source=twitter&utm_medium=social&page=2');\n * // Returns \"https://example.com?page=2\"\n *\n * // URL without UTM parameters (unchanged)\n * getUrlWithoutUTMParams('https://example.com?page=2&category=shoes');\n * // Returns \"https://example.com?page=2&category=shoes\"\n *\n * // With invalid URL\n * getUrlWithoutUTMParams('not-a-url');\n * // Returns \"not-a-url\" (unchanged)\n *\n * // Use for clean sharing URLs\n * const shareUrl = getUrlWithoutUTMParams(window.location.href);\n * navigator.share({ url: shareUrl });\n *\n * // Use for canonical URLs\n * const canonicalUrl = getUrlWithoutUTMParams(currentUrl);\n * document.querySelector('link[rel=\"canonical\"]').href = canonicalUrl;\n *\n * // Use in analytics to group by clean URL\n * const cleanUrl = getUrlWithoutUTMParams(pageUrl);\n * analytics.track('page_view', { clean_url: cleanUrl });\n * ```\n */\nexport const getUrlWithoutUTMParams = (url: string): string => {\n try {\n const newURL = new URL(url);\n // Strip every recognized UTM/ref tag. Iterate UTMTags directly so adding a\n // new tag in one place automatically extends the strip list.\n for (const key of UTMTags) {\n newURL.searchParams.delete(key);\n }\n return newURL.toString();\n } catch (_) {\n return url;\n }\n};\n\n/**\n * Creates a URL with optional UTM parameters for a specific domain\n * Useful for generating links with tracking parameters\n *\n * @param href - The base URL or path\n * @param domain - The domain to check against\n * @param utmParams - Optional UTM parameters to add to the URL\n * @returns A formatted URL with UTM parameters if applicable\n *\n * @example\n * ```typescript\n * import { createHref, UTMTags } from '@kumix/utils';\n *\n * // Basic usage\n * createHref('/features', 'example.com');\n * // Returns \"https://domain.com/features\" (with domain transformation)\n *\n * // With UTM parameters\n * createHref('/features', 'example.com', {\n * utm_source: 'twitter',\n * utm_medium: 'social'\n * });\n * // Returns \"https://domain.com/features?utm_source=twitter&utm_medium=social\"\n *\n * // With special domain case\n * createHref('/features', 'domain.com');\n * // Returns \"/features\" (unchanged)\n *\n * // With absolute URL\n * createHref('https://example.com/page', 'example.com');\n * // Returns \"https://example.com/page\"\n *\n * // Use in navigation components\n * const navLinks = [\n * { href: createHref('/pricing', domain, { utm_source: 'nav' }), label: 'Pricing' },\n * { href: createHref('/features', domain, { utm_source: 'nav' }), label: 'Features' }\n * ];\n * ```\n */\nexport const createHref = (\n href: string,\n domain: string,\n // any params, doesn't have to be all of them\n utmParams?: Partial<Record<(typeof UTMTags)[number], string>>,\n): string => {\n // Normalize the domain so we can always feed a valid absolute URL into the\n // URL constructor. Accepts inputs like \"example.com\", \"https://example.com\",\n // or \"https://example.com/\" without throwing.\n const hasScheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:\\/\\//.test(domain);\n const base = hasScheme ? domain : `https://${domain}`;\n const normalizedBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const path = href.startsWith(\"/\") ? href : `/${href}`;\n\n let url: URL;\n try {\n url = new URL(`${normalizedBase}${path}`);\n } catch (_) {\n return \"\";\n }\n\n if (utmParams) {\n Object.entries(utmParams).forEach(([key, value]) => {\n if (typeof value === \"string\" && value.length > 0) {\n url.searchParams.set(key, value);\n }\n });\n }\n return url.toString();\n};\n","/**\n * Utility function for deep object comparison\n * Provides recursive comparison of nested objects and arrays\n */\n\n/**\n * Type definition for the deepEqual function\n * Specifies the function signature for comparing two objects deeply\n */\ntype DeepEqual = (obj1: Record<string, unknown>, obj2: Record<string, unknown>) => boolean;\n\n/**\n * Performs a deep equality check between two objects\n * Recursively compares all nested properties and values\n *\n * @param obj1 - First object to compare\n * @param obj2 - Second object to compare\n * @returns True if objects are deeply equal, false otherwise\n *\n * @example\n * ```ts\n * import { deepEqual } from '@/utils/functions';\n *\n * // Simple objects\n * deepEqual({ a: 1, b: 2 }, { a: 1, b: 2 })\n * // Returns true\n *\n * // Different order of keys doesn't matter\n * deepEqual({ a: 1, b: 2 }, { b: 2, a: 1 })\n * // Returns true\n *\n * // Nested objects\n * deepEqual(\n * { a: 1, b: { c: 3, d: 4 } },\n * { a: 1, b: { c: 3, d: 4 } }\n * )\n * // Returns true\n *\n * // Different values\n * deepEqual({ a: 1, b: 2 }, { a: 1, b: 3 })\n * // Returns false\n *\n * // Different structure\n * deepEqual({ a: 1, b: 2 }, { a: 1, c: 2 })\n * // Returns false\n *\n * // Different nesting\n * deepEqual(\n * { a: 1, b: { c: 3 } },\n * { a: 1, b: { c: 4 } }\n * )\n * // Returns false\n * ```\n */\nexport const deepEqual: DeepEqual = (obj1, obj2) => {\n if (obj1 === obj2) {\n return true;\n }\n\n if (typeof obj1 !== \"object\" || typeof obj2 !== \"object\" || obj1 === null || obj2 === null) {\n return false;\n }\n\n // Compare by type tag to distinguish Date, RegExp, Map, Set, Array, etc.\n const tag1 = Object.prototype.toString.call(obj1);\n const tag2 = Object.prototype.toString.call(obj2);\n if (tag1 !== tag2) {\n return false;\n }\n\n // Handle Date — compare by time value\n if (obj1 instanceof Date && obj2 instanceof Date) {\n return obj1.getTime() === obj2.getTime();\n }\n\n // Handle RegExp — compare source and flags\n if (obj1 instanceof RegExp && obj2 instanceof RegExp) {\n return obj1.source === obj2.source && obj1.flags === obj2.flags;\n }\n\n // Handle arrays — compare length first, then elements in order\n if (Array.isArray(obj1) && Array.isArray(obj2)) {\n if (obj1.length !== obj2.length) {\n return false;\n }\n for (let i = 0; i < obj1.length; i++) {\n if (!deepEqual(obj1[i] as Record<string, unknown>, obj2[i] as Record<string, unknown>)) {\n return false;\n }\n }\n return true;\n }\n\n // Handle Map — compare size, then every key/value pair (order-sensitive, like array)\n if (obj1 instanceof Map && obj2 instanceof Map) {\n if (obj1.size !== obj2.size) {\n return false;\n }\n for (const [key, value] of obj1) {\n if (!obj2.has(key)) {\n return false;\n }\n if (!deepEqual(value as Record<string, unknown>, obj2.get(key) as Record<string, unknown>)) {\n return false;\n }\n }\n return true;\n }\n\n // Handle Set — compare size, then every element (deepEqual to support object members)\n if (obj1 instanceof Set && obj2 instanceof Set) {\n if (obj1.size !== obj2.size) {\n return false;\n }\n for (const value of obj1) {\n // Sets don't have deep lookup, so check each candidate of obj2.\n let found = false;\n for (const other of obj2) {\n if (deepEqual(value as Record<string, unknown>, other as Record<string, unknown>)) {\n found = true;\n break;\n }\n }\n if (!found) {\n return false;\n }\n }\n return true;\n }\n\n const keys1 = Object.keys(obj1);\n const keys2 = Object.keys(obj2);\n\n if (keys1.length !== keys2.length) {\n return false;\n }\n\n for (const key of keys1) {\n if (!keys2.includes(key)) {\n return false;\n }\n\n const val1 = obj1[key];\n const val2 = obj2[key];\n\n // If both values are objects, recursively compare them\n if (typeof val1 === \"object\" && val1 !== null && typeof val2 === \"object\" && val2 !== null) {\n if (!deepEqual(val1 as Record<string, unknown>, val2 as Record<string, unknown>)) {\n return false;\n }\n } else if (val1 !== val2) {\n // For non-object values, use strict equality\n return false;\n }\n }\n\n return true;\n};\n","/**\n * Email validation and formatting utilities for SaaS applications\n * Provides comprehensive email validation, normalization, and domain checking\n * Includes support for disposable email detection and business email validation\n */\n\n/**\n * Interface for email validation result\n */\ninterface EmailValidationResult {\n /** Whether the email is valid */\n isValid: boolean;\n /** Normalized email address */\n normalized?: string;\n /** Error message if validation failed */\n error?: string;\n /** Additional validation details */\n details?: {\n /** Whether the domain appears to be disposable */\n isDisposable?: boolean;\n /** Whether the email appears to be a business email */\n isBusiness?: boolean;\n /** The domain part of the email */\n domain?: string;\n };\n}\n\n/**\n * Common disposable email domains\n * Used to detect temporary/throwaway email addresses\n */\nconst DISPOSABLE_EMAIL_DOMAINS = new Set([\n \"10minutemail.com\",\n \"guerrillamail.com\",\n \"mailinator.com\",\n \"tempmail.org\",\n \"yopmail.com\",\n \"temp-mail.org\",\n \"throwaway.email\",\n \"getnada.com\",\n \"maildrop.cc\",\n \"sharklasers.com\",\n \"guerrillamailblock.com\",\n \"pokemail.net\",\n \"spam4.me\",\n \"bccto.me\",\n \"chacuo.net\",\n \"dispostable.com\",\n \"fakeinbox.com\",\n \"hide.biz.st\",\n \"mytrashmail.com\",\n \"nobulk.com\",\n \"sogetthis.com\",\n \"spamherelots.com\",\n \"spamhereplease.com\",\n \"spamthisplease.com\",\n \"superrito.com\",\n \"tempemail.com\",\n \"thankyou2010.com\",\n \"trash2009.com\",\n \"trashymail.com\",\n \"tyldd.com\",\n]);\n\n/**\n * Free email providers\n * Used to distinguish between free and business email addresses\n */\nconst FREE_EMAIL_DOMAINS = new Set([\n \"gmail.com\",\n \"yahoo.com\",\n \"hotmail.com\",\n \"outlook.com\",\n \"aol.com\",\n \"icloud.com\",\n \"protonmail.com\",\n \"mail.com\",\n \"yandex.com\",\n \"zoho.com\",\n \"fastmail.com\",\n \"tutanota.com\",\n]);\n\n/**\n * Validates an email address with comprehensive checks\n *\n * @param email - The email address to validate\n * @param options - Validation options\n * @returns Validation result with details\n *\n * @example\n * ```typescript\n * import { validateEmail } from '@kumix/utils';\n *\n * // Basic validation\n * const result = validateEmail('user@example.com');\n * if (result.isValid) {\n * console.log('Valid email:', result.normalized);\n * }\n *\n * // Check for disposable emails\n * const result = validateEmail('test@10minutemail.com');\n * if (result.details?.isDisposable) {\n * throw new Error('Disposable emails are not allowed');\n * }\n *\n * // Business email validation\n * const result = validateEmail('john@company.com');\n * if (result.details?.isBusiness) {\n * // Apply business-specific logic\n * await createBusinessAccount(result.normalized);\n * }\n *\n * // In user registration\n * async function registerUser(email: string, password: string) {\n * const emailResult = validateEmail(email);\n * if (!emailResult.isValid) {\n * throw new Error(emailResult.error || 'Invalid email');\n * }\n *\n * if (emailResult.details?.isDisposable) {\n * throw new Error('Please use a permanent email address');\n * }\n *\n * await createUser({\n * email: emailResult.normalized,\n * password: await hashPassword(password)\n * });\n * }\n * ```\n */\nexport function validateEmail(\n email: string,\n options: {\n /** Whether to allow disposable emails (default: true) */\n allowDisposable?: boolean;\n /** Whether to require business emails (default: false) */\n requireBusiness?: boolean;\n } = {},\n): EmailValidationResult {\n const { allowDisposable = true, requireBusiness = false } = options;\n\n // Basic validation\n if (!email || typeof email !== \"string\") {\n return {\n isValid: false,\n error: \"Email must be a non-empty string\",\n };\n }\n\n const trimmedEmail = email.trim().toLowerCase();\n\n if (trimmedEmail.length === 0) {\n return {\n isValid: false,\n error: \"Email cannot be empty\",\n };\n }\n\n // RFC 5322 compliant email regex (simplified but robust)\n const emailRegex =\n /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;\n\n if (!emailRegex.test(trimmedEmail)) {\n return {\n isValid: false,\n error: \"Invalid email format\",\n };\n }\n\n // Extract domain\n const domain = trimmedEmail.split(\"@\")[1];\n if (!domain) {\n return {\n isValid: false,\n error: \"Invalid email format - missing domain\",\n };\n }\n\n // Check for disposable email\n const isDisposable = DISPOSABLE_EMAIL_DOMAINS.has(domain);\n if (!allowDisposable && isDisposable) {\n return {\n isValid: false,\n error: \"Disposable email addresses are not allowed\",\n details: { isDisposable: true, domain },\n };\n }\n\n // Check for business email\n const isFreeEmail = FREE_EMAIL_DOMAINS.has(domain);\n const isBusiness = !isFreeEmail && !isDisposable;\n\n if (requireBusiness && !isBusiness) {\n return {\n isValid: false,\n error: \"Business email address is required\",\n details: { isBusiness: false, domain },\n };\n }\n\n return {\n isValid: true,\n normalized: trimmedEmail,\n details: {\n isDisposable,\n isBusiness,\n domain,\n },\n };\n}\n\n/**\n * Normalizes an email address for consistent storage and comparison\n *\n * @param email - The email address to normalize\n * @returns Normalized email address or null if invalid\n *\n * @example\n * ```typescript\n * import { normalizeEmail } from '@kumix/utils';\n *\n * // Basic normalization\n * const normalized = normalizeEmail(' USER@EXAMPLE.COM ');\n * // Returns: 'user@example.com'\n *\n * // Gmail-specific normalization\n * const normalized = normalizeEmail('user.name+tag@gmail.com');\n * // Returns: 'username@gmail.com'\n *\n * // In user lookup\n * async function findUserByEmail(email: string) {\n * const normalizedEmail = normalizeEmail(email);\n * if (!normalizedEmail) {\n * throw new Error('Invalid email format');\n * }\n *\n * return await User.findOne({ email: normalizedEmail });\n * }\n * ```\n */\nexport function normalizeEmail(email: string): string | null {\n const result = validateEmail(email);\n if (!result.isValid || !result.normalized) {\n return null;\n }\n\n let normalized = result.normalized;\n const [localPart, domain] = normalized.split(\"@\");\n\n // Gmail-specific normalization\n if (domain === \"gmail.com\") {\n // Remove dots and everything after +\n const cleanLocal = localPart.replace(/\\./g, \"\").split(\"+\")[0];\n normalized = `${cleanLocal}@${domain}`;\n }\n\n // Outlook/Hotmail-specific normalization\n if ([\"outlook.com\", \"hotmail.com\", \"live.com\"].includes(domain)) {\n // Remove everything after +\n const cleanLocal = localPart.split(\"+\")[0];\n normalized = `${cleanLocal}@${domain}`;\n }\n\n return normalized;\n}\n\n/**\n * Checks if an email domain is disposable/temporary\n *\n * @param email - The email address to check\n * @returns True if the domain is disposable\n *\n * @example\n * ```typescript\n * import { isDisposableEmail } from '@kumix/utils';\n *\n * // Check for disposable email\n * if (isDisposableEmail('test@10minutemail.com')) {\n * throw new Error('Please use a permanent email address');\n * }\n *\n * // In email validation middleware\n * function validateUserEmail(email: string) {\n * if (isDisposableEmail(email)) {\n * return {\n * valid: false,\n * error: 'Temporary email addresses are not allowed'\n * };\n * }\n * return { valid: true };\n * }\n * ```\n */\nexport function isDisposableEmail(email: string): boolean {\n const result = validateEmail(email);\n return result.details?.isDisposable || false;\n}\n\n/**\n * Checks if an email appears to be a business email\n *\n * @param email - The email address to check\n * @returns True if the email appears to be business-related\n *\n * @example\n * ```typescript\n * import { isBusinessEmail } from '@kumix/utils';\n *\n * // Check for business email\n * if (isBusinessEmail('john@company.com')) {\n * // Apply business account features\n * await enableBusinessFeatures(user);\n * }\n *\n * // In pricing logic\n * function getAccountType(email: string) {\n * return isBusinessEmail(email) ? 'business' : 'personal';\n * }\n * ```\n */\nexport function isBusinessEmail(email: string): boolean {\n const result = validateEmail(email);\n return result.details?.isBusiness || false;\n}\n\n/**\n * Extracts the domain from an email address\n *\n * @param email - The email address\n * @returns The domain part or null if invalid\n *\n * @example\n * ```typescript\n * import { getEmailDomain } from '@kumix/utils';\n *\n * // Extract domain\n * const domain = getEmailDomain('user@example.com');\n * // Returns: 'example.com'\n *\n * // Domain-based logic\n * function getCompanyFromEmail(email: string) {\n * const domain = getEmailDomain(email);\n * if (domain) {\n * return domain.split('.')[0]; // 'example' from 'example.com'\n * }\n * return null;\n * }\n * ```\n */\nexport function getEmailDomain(email: string): string | null {\n const result = validateEmail(email);\n return result.details?.domain || null;\n}\n","/**\n * Utility function for iframe embedding validation\n * Checks if a URL can be embedded in an iframe based on security headers\n */\n\n/**\n * Determines if a URL can be displayed in an iframe by checking security headers.\n * Examines Content-Security-Policy `frame-ancestors` and `X-Frame-Options` headers.\n *\n * A URL is considered embeddable only when:\n * - `frame-ancestors` is absent OR explicitly allows `*` / `self` (same origin) /\n * a wildcard/origin that matches `requestDomain`, AND\n * - `X-Frame-Options` is not `DENY` or `SAMEORIGIN` (when origin differs).\n *\n * @param options - The options for the check\n * @param options.url - The URL to check for iframe embedding capability\n * @param options.requestDomain - The origin that will be embedding the iframe\n * (e.g. `https://myapp.com`). Compared against CSP source expressions.\n * @returns A Promise that resolves to true if the URL can be embedded, false otherwise.\n *\n * @example\n * ```ts\n * import { isIframeable } from '@/utils/functions';\n *\n * const canEmbed = await isIframeable({\n * url: 'https://example.com',\n * requestDomain: 'https://myapp.com'\n * });\n * ```\n */\nexport const isIframeable = async ({\n url,\n requestDomain,\n}: {\n url: string;\n requestDomain: string;\n}): Promise<boolean> => {\n const res = await fetch(url);\n\n const normalizeOrigin = (value: string) => value.trim().replace(/\\/$/, \"\").toLowerCase();\n const requestedOrigin = normalizeOrigin(requestDomain);\n\n // 1. Content-Security-Policy: frame-ancestors (CSP Level 2).\n // If present, it is the authoritative source for embeddability — it OVERRIDES\n // X-Frame-Options per the CSP spec.\n const cspHeader = res.headers.get(\"content-security-policy\");\n if (cspHeader) {\n const frameAncestorsMatch = cspHeader.match(/frame-ancestors\\s+([\\s\\S]+?)(?=;|$)/i);\n if (frameAncestorsMatch) {\n const sources = frameAncestorsMatch[1].trim().split(/\\s+/).filter(Boolean);\n\n const isAllowed = sources.some((source) => {\n const s = source.toLowerCase();\n if (s === \"'none'\") return false;\n if (s === \"*\" || s === \"https:*\" || s === \"http:*\") return true;\n if (s === \"'self'\") {\n // 'self' means same origin as the framed document, not the embedder.\n // We can't reliably know the embedder matches without comparing to the\n // response URL's origin, so treat conservatively as a match only when\n // the request domain matches the target URL origin.\n try {\n const targetOrigin = normalizeOrigin(new URL(res.url).origin);\n return targetOrigin === requestedOrigin;\n } catch {\n return false;\n }\n }\n // Wildcard scheme/host like https://*.example.com\n if (s.includes(\"*\")) {\n const pattern = s.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(`^${pattern}$`).test(requestedOrigin);\n }\n return normalizeOrigin(s) === requestedOrigin;\n });\n\n // frame-ancestors is authoritative: if it doesn't list us, we are blocked,\n // regardless of X-Frame-Options.\n return isAllowed;\n }\n }\n\n // 2. X-Frame-Options (legacy, CVE-prone). Only consulted when no frame-ancestors.\n const xFrameOptions = res.headers.get(\"X-Frame-Options\");\n if (xFrameOptions) {\n const value = xFrameOptions.trim().toUpperCase();\n if (value === \"DENY\") {\n return false;\n }\n if (value === \"SAMEORIGIN\") {\n try {\n return normalizeOrigin(new URL(res.url).origin) === requestedOrigin;\n } catch {\n return false;\n }\n }\n // \"ALLOW-FROM\" is deprecated and unsupported; treat as not embeddable.\n if (value.startsWith(\"ALLOW-FROM\")) {\n return false;\n }\n }\n\n return true;\n};\n","/**\n * Utility functions for key validation and management\n * Provides tools for validating and checking special keys in the system\n */\n\n/**\n * Regular expression for validating keys\n * Allows letters, numbers, '-', '_', '/', '.', and emojis\n *\n * @example\n * ```ts\n * import { validKeyRegex } from '@/utils/functions';\n *\n * // Check if a key is valid\n * const isValidKey = (key: string) => validKeyRegex.test(key);\n *\n * isValidKey('user-profile') // true\n * isValidKey('path/to/resource') // true\n * isValidKey('emoji-😊-key') // true\n * isValidKey('<invalid>') // false\n * ```\n */\nexport const validKeyRegex = new RegExp(/^[0-9A-Za-z_\\u0080-\\uFFFF/\\p{Emoji}.-]+$/u);\n\n/**\n * Checks if a key is unsupported by the system\n * Validates against excluded prefixes and suffixes\n * Special case for '_root' which is always supported\n *\n * @param key - The key to check\n * @returns True if the key is unsupported, false otherwise\n *\n * @example\n * ```ts\n * import { isUnsupportedKey } from '@/utils/functions';\n *\n * isUnsupportedKey('normal-key') // false\n * isUnsupportedKey('_root') // false (special case)\n * isUnsupportedKey('.well-known/acme-challenge') // true\n * isUnsupportedKey('script.php') // true\n * ```\n */\nexport const isUnsupportedKey = (key: string): boolean => {\n // special case for root domain links\n if (key === \"_root\") {\n return false;\n }\n const excludedPrefix = [\".well-known\"];\n const excludedSuffix = [\".php\", \".php7\"];\n return (\n excludedPrefix.some((prefix) => key.startsWith(prefix)) ||\n excludedSuffix.some((suffix) => key.endsWith(suffix))\n );\n};\n\n/**\n * Checks if a key is globally reserved by the system\n * These keys are reserved for special system files and cannot be used by users\n *\n * @param key - The key to check\n * @returns True if the key is globally reserved, false otherwise\n *\n * @example\n * ```ts\n * import { isReservedKeyGlobal } from '@/utils/functions';\n *\n * isReservedKeyGlobal('favicon.ico') // true\n * isReservedKeyGlobal('robots.txt') // true\n * isReservedKeyGlobal('custom-page') // false\n *\n * // Validate user input\n * function validateUserKey(key: string) {\n * if (isReservedKeyGlobal(key)) {\n * return 'This key is reserved for system use';\n * }\n * return null; // Valid\n * }\n * ```\n */\nexport const isReservedKeyGlobal = (key: string): boolean => {\n const reservedKeys = [\n \"favicon.ico\",\n \"sitemap.xml\",\n \"robots.txt\",\n \"manifest.webmanifest\",\n \"manifest.json\",\n \"apple-app-site-association\",\n ];\n return reservedKeys.includes(key);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,MAAa,8BAA8B;CACzC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/HA,MAAa,aAAwC;CACnD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,kBAAkB,OAAO,KAAK,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7BrD,MAAa,YAAuC;CAClD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,gBAAgB,OAAO,KAAK,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgClD,MAAa,mBAAmB;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5UA,MAAa,sBAAiD;CAC5D,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AAON;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpPA,MAAa,UAAqC;CAChD,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,UAAU;CACV,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;AACX;AAEA,MAAa,eAAe,OAAO,KAAK,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC16G/C,MAAa,yBAAS,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAC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"}
1
+ {"version":3,"file":"index.js","names":["slugify"],"sources":["../src/constants/country/connect-supported-countries.ts","../src/constants/country/continents.ts","../src/constants/country/countries.ts","../src/constants/country/country-phone-codes.ts","../src/constants/country/regions.ts","../src/constants/domain/cctlds.ts","../src/constants/domain/second.ts","../src/constants/domain/special.ts","../src/constants/colors.ts","../src/constants/env.ts","../src/constants/framer-motion.ts","../src/constants/localhost.ts","../src/constants/reserved-slugs.ts","../src/functions/analytics/google.ts","../src/functions/array/chunk.ts","../src/functions/array/random-value.ts","../src/functions/array/stable-sort.ts","../src/functions/string/assets.ts","../src/functions/browser/construct-metadata.ts","../src/functions/browser/cookies.ts","../src/functions/browser/get-height.ts","../src/functions/browser/resize-image.ts","../src/functions/browser/storage.ts","../src/functions/crypto/base-id.ts","../src/functions/crypto/cuid.ts","../src/functions/crypto/hash-string.ts","../src/functions/crypto/nanoid.ts","../src/functions/datetime/billing-utils.ts","../src/functions/datetime/format-date.ts","../src/functions/datetime/format-datetime-smart.ts","../src/functions/datetime/format-datetime.ts","../src/functions/datetime/format-period.ts","../src/functions/datetime/format-time.ts","../src/functions/datetime/get-datetime-local.ts","../src/functions/datetime/get-days-difference.ts","../src/functions/datetime/get-first-and-last-day.ts","../src/functions/datetime/get-year.ts","../src/functions/datetime/time-ago.ts","../src/functions/datetime/timezone.ts","../src/functions/file/format-file-size.ts","../src/functions/http/fetch-with-retry.ts","../src/functions/http/fetch-with-timeout.ts","../src/functions/http/fetcher.ts","../src/functions/http/ip.ts","../src/functions/http/parse-request.ts","../src/functions/http/recaptcha.ts","../src/functions/logging/slack-log.ts","../src/functions/performance/debounce.ts","../src/functions/performance/throttle.ts","../src/functions/string/auth.ts","../src/functions/string/camel-case.ts","../src/functions/string/capitalize.ts","../src/functions/string/cn.ts","../src/functions/string/combine-words.ts","../src/functions/string/currency-formatter.ts","../src/functions/string/get-initials.ts","../src/functions/string/nformatter.ts","../src/functions/string/normalize-string.ts","../src/functions/string/pluralize.ts","../src/functions/string/regex-escape.ts","../src/functions/string/truncate.ts","../src/functions/string/smart-truncate.ts","../src/functions/string/trim.ts","../src/functions/url/url-validation.ts","../src/functions/url/domains.ts","../src/functions/url/link-constructor.ts","../src/functions/url/search-params.ts","../src/functions/url/url-conversion.ts","../src/functions/url/url-formatting.ts","../src/functions/url/utm-params.ts","../src/functions/validation/deep-equal.ts","../src/functions/validation/email.ts","../src/functions/validation/is-iframeable.ts","../src/functions/validation/keys.ts"],"sourcesContent":["/**\n * Connect Supported Countries\n * Provides a list of country codes supported by the Connect API/service\n */\n\n/**\n * Array of ISO 3166-1 alpha-2 country codes supported by the Connect service\n * Each code is accompanied by a comment with the country name for reference\n *\n * @example\n * ```ts\n * import { CONNECT_SUPPORTED_COUNTRIES } from '@kumix/utils';\n *\n * // Check if a country is supported\n * const isSupported = CONNECT_SUPPORTED_COUNTRIES.includes('US'); // true\n *\n * // Filter users by supported countries\n * const users = [\n * { name: 'John', country: 'US' },\n * { name: 'Alice', country: 'FR' },\n * { name: 'Bob', country: 'ZZ' } // Not supported\n * ];\n * const supportedUsers = users.filter(user =>\n * CONNECT_SUPPORTED_COUNTRIES.includes(user.country)\n * ); // Returns users from US and FR\n *\n * // Display supported countries in a dropdown\n * const countryOptions = CONNECT_SUPPORTED_COUNTRIES.map(code => ({\n * value: code,\n * label: new Intl.DisplayNames(['en'], { type: 'region' }).of(code)\n * }));\n * ```\n */\nexport const CONNECT_SUPPORTED_COUNTRIES = [\n \"AL\", // Albania\n \"DZ\", // Algeria\n \"AO\", // Angola\n \"AG\", // Antigua & Barbuda\n \"AR\", // Argentina\n \"AM\", // Armenia\n \"AU\", // Australia\n \"AT\", // Austria\n \"AZ\", // Azerbaijan\n \"BS\", // Bahamas\n \"BH\", // Bahrain\n \"BD\", // Bangladesh\n \"BE\", // Belgium\n \"BJ\", // Benin\n \"BT\", // Bhutan\n \"BO\", // Bolivia\n \"BA\", // Bosnia & Herzegovina\n \"BW\", // Botswana\n \"BN\", // Brunei\n \"BG\", // Bulgaria\n \"KH\", // Cambodia\n \"CA\", // Canada\n \"CL\", // Chile\n \"CO\", // Colombia\n \"CR\", // Costa Rica\n \"CI\", // Côte d'Ivoire\n \"HR\", // Croatia\n \"CY\", // Cyprus\n \"CZ\", // Czech Republic\n \"DK\", // Denmark\n \"DO\", // Dominican Republic\n \"EC\", // Ecuador\n \"EG\", // Egypt\n \"SV\", // El Salvador\n \"EE\", // Estonia\n \"ET\", // Ethiopia\n \"FI\", // Finland\n \"FR\", // France\n \"GA\", // Gabon\n \"GM\", // Gambia\n \"DE\", // Germany\n \"GH\", // Ghana\n \"GR\", // Greece\n \"GT\", // Guatemala\n \"GY\", // Guyana\n \"HK\", // Hong Kong\n \"HU\", // Hungary\n \"IS\", // Iceland\n \"IN\", // India\n \"ID\", // Indonesia\n \"IE\", // Ireland\n \"IL\", // Israel\n \"IT\", // Italy\n \"JM\", // Jamaica\n \"JP\", // Japan\n \"JO\", // Jordan\n \"KZ\", // Kazakhstan\n \"KE\", // Kenya\n \"KW\", // Kuwait\n \"LA\", // Laos\n \"LV\", // Latvia\n \"LI\", // Liechtenstein\n \"LT\", // Lithuania\n \"LU\", // Luxembourg\n \"MO\", // Macao SAR China\n \"MG\", // Madagascar\n \"MY\", // Malaysia\n \"MT\", // Malta\n \"MU\", // Mauritius\n \"MX\", // Mexico\n \"MD\", // Moldova\n \"MC\", // Monaco\n \"MN\", // Mongolia\n \"MA\", // Morocco\n \"MZ\", // Mozambique\n \"NA\", // Namibia\n \"NL\", // Netherlands\n \"NZ\", // New Zealand\n \"NE\", // Niger\n \"NG\", // Nigeria\n \"MK\", // North Macedonia\n \"NO\", // Norway\n \"OM\", // Oman\n \"PK\", // Pakistan\n \"PA\", // Panama\n \"PY\", // Paraguay\n \"PE\", // Peru\n \"PH\", // Philippines\n \"PL\", // Poland\n \"PT\", // Portugal\n \"QA\", // Qatar\n \"RO\", // Romania\n \"RW\", // Rwanda\n \"SM\", // San Marino\n \"SA\", // Saudi Arabia\n \"SN\", // Senegal\n \"RS\", // Serbia\n \"SG\", // Singapore\n \"SK\", // Slovakia\n \"SI\", // Slovenia\n \"ZA\", // South Africa\n \"KR\", // South Korea\n \"ES\", // Spain\n \"LK\", // Sri Lanka\n \"LC\", // St. Lucia\n \"SE\", // Sweden\n \"CH\", // Switzerland\n \"TW\", // Taiwan\n \"TZ\", // Tanzania\n \"TH\", // Thailand\n \"TT\", // Trinidad & Tobago\n \"TN\", // Tunisia\n \"TR\", // Turkey\n \"AE\", // United Arab Emirates\n \"GB\", // United Kingdom\n \"US\", // United States\n \"UY\", // Uruguay\n \"UZ\", // Uzbekistan\n \"VN\", // Vietnam\n];\n","/**\n * Continent Constants\n * Provides mapping between continent codes and names\n */\n\n/**\n * Object mapping continent codes to their full names\n * Uses standard continent codes as keys\n *\n * @example\n * ```ts\n * import { CONTINENTS } from '@kumix/utils';\n *\n * // Get continent name from code\n * const continentName = CONTINENTS['EU']; // 'Europe'\n *\n * // Check if a code is a valid continent\n * const isValidContinent = 'AS' in CONTINENTS; // true\n *\n * // Display all continents in a dropdown\n * const continentOptions = Object.entries(CONTINENTS).map(([code, name]) => ({\n * value: code,\n * label: name\n * }));\n * ```\n */\nexport const CONTINENTS: { [key: string]: string } = {\n AF: \"Africa\",\n AN: \"Antarctica\",\n AS: \"Asia\",\n EU: \"Europe\",\n NA: \"North America\",\n OC: \"Oceania\",\n SA: \"South America\",\n};\n\n/**\n * Array of all continent codes\n * Useful for iteration, validation, and type checking\n *\n * @example\n * ```ts\n * import { CONTINENT_CODES } from '@kumix/utils';\n *\n * // Validate user input\n * const isValidContinentCode = (code: string) => CONTINENT_CODES.includes(code);\n *\n * // Create a filter for continents\n * const continentFilters = CONTINENT_CODES.map(code => ({\n * id: code,\n * name: CONTINENTS[code],\n * selected: false\n * }));\n * ```\n */\nexport const CONTINENT_CODES = Object.keys(CONTINENTS) as [string, ...string[]];\n","/**\n * Country Constants\n * Provides comprehensive mappings for country codes and names\n */\n\n/**\n * Object mapping ISO 3166-1 alpha-2 country codes to their full names\n * Contains all recognized countries and territories worldwide\n *\n * @example\n * ```ts\n * import { COUNTRIES } from '@kumix/utils';\n *\n * // Get country name from code\n * const countryName = COUNTRIES['US']; // 'United States'\n *\n * // Check if a code is a valid country\n * const isValidCountry = 'FR' in COUNTRIES; // true\n *\n * // Display all countries in a dropdown\n * const countryOptions = Object.entries(COUNTRIES).map(([code, name]) => ({\n * value: code,\n * label: name\n * }));\n * ```\n */\nexport const COUNTRIES: { [key: string]: string } = {\n AF: \"Afghanistan\",\n AL: \"Albania\",\n DZ: \"Algeria\",\n AS: \"American Samoa\",\n AD: \"Andorra\",\n AO: \"Angola\",\n AI: \"Anguilla\",\n AQ: \"Antarctica\",\n AG: \"Antigua and Barbuda\",\n AR: \"Argentina\",\n AM: \"Armenia\",\n AW: \"Aruba\",\n AU: \"Australia\",\n AT: \"Austria\",\n AZ: \"Azerbaijan\",\n BS: \"Bahamas\",\n BH: \"Bahrain\",\n BD: \"Bangladesh\",\n BB: \"Barbados\",\n BY: \"Belarus\",\n BE: \"Belgium\",\n BZ: \"Belize\",\n BJ: \"Benin\",\n BM: \"Bermuda\",\n BT: \"Bhutan\",\n BO: \"Bolivia\",\n BA: \"Bosnia and Herzegovina\",\n BW: \"Botswana\",\n BV: \"Bouvet Island\",\n BR: \"Brazil\",\n IO: \"British Indian Ocean Territory\",\n BN: \"Brunei Darussalam\",\n BG: \"Bulgaria\",\n BF: \"Burkina Faso\",\n BI: \"Burundi\",\n KH: \"Cambodia\",\n CM: \"Cameroon\",\n CA: \"Canada\",\n CV: \"Cape Verde\",\n KY: \"Cayman Islands\",\n CF: \"Central African Republic\",\n TD: \"Chad\",\n CL: \"Chile\",\n CN: \"China\",\n CX: \"Christmas Island\",\n CC: \"Cocos (Keeling) Islands\",\n CO: \"Colombia\",\n KM: \"Comoros\",\n CG: \"Congo (Republic)\",\n CD: \"Congo (Democratic Republic)\",\n CK: \"Cook Islands\",\n CR: \"Costa Rica\",\n CI: \"Ivory Coast\",\n HR: \"Croatia\",\n CU: \"Cuba\",\n CY: \"Cyprus\",\n CZ: \"Czech Republic\",\n DK: \"Denmark\",\n DJ: \"Djibouti\",\n DM: \"Dominica\",\n DO: \"Dominican Republic\",\n EC: \"Ecuador\",\n EG: \"Egypt\",\n SV: \"El Salvador\",\n GQ: \"Equatorial Guinea\",\n ER: \"Eritrea\",\n EE: \"Estonia\",\n ET: \"Ethiopia\",\n FK: \"Falkland Islands\",\n FO: \"Faroe Islands\",\n FJ: \"Fiji\",\n FI: \"Finland\",\n FR: \"France\",\n GF: \"French Guiana\",\n PF: \"French Polynesia\",\n TF: \"French Southern Territories\",\n GA: \"Gabon\",\n GM: \"Gambia\",\n GE: \"Georgia\",\n DE: \"Germany\",\n GH: \"Ghana\",\n GI: \"Gibraltar\",\n GR: \"Greece\",\n GL: \"Greenland\",\n GD: \"Grenada\",\n GP: \"Guadeloupe\",\n GU: \"Guam\",\n GT: \"Guatemala\",\n GN: \"Guinea\",\n GW: \"Guinea-Bissau\",\n GY: \"Guyana\",\n HT: \"Haiti\",\n HM: \"Heard Island and McDonald Islands\",\n VA: \"Vatican City\",\n HN: \"Honduras\",\n HK: \"Hong Kong\",\n HU: \"Hungary\",\n IS: \"Iceland\",\n IN: \"India\",\n ID: \"Indonesia\",\n IR: \"Iran\",\n IQ: \"Iraq\",\n IE: \"Ireland\",\n IL: \"Israel\",\n IT: \"Italy\",\n JM: \"Jamaica\",\n JP: \"Japan\",\n JO: \"Jordan\",\n KZ: \"Kazakhstan\",\n KE: \"Kenya\",\n KI: \"Kiribati\",\n KP: \"North Korea\",\n KR: \"South Korea\",\n KW: \"Kuwait\",\n KG: \"Kyrgyzstan\",\n LA: \"Laos\",\n LV: \"Latvia\",\n LB: \"Lebanon\",\n LS: \"Lesotho\",\n LR: \"Liberia\",\n LY: \"Libya\",\n LI: \"Liechtenstein\",\n LT: \"Lithuania\",\n LU: \"Luxembourg\",\n MO: \"Macao\",\n MG: \"Madagascar\",\n MW: \"Malawi\",\n MY: \"Malaysia\",\n MV: \"Maldives\",\n ML: \"Mali\",\n MT: \"Malta\",\n MH: \"Marshall Islands\",\n MQ: \"Martinique\",\n MR: \"Mauritania\",\n MU: \"Mauritius\",\n YT: \"Mayotte\",\n MX: \"Mexico\",\n FM: \"Micronesia\",\n MD: \"Moldova\",\n MC: \"Monaco\",\n MN: \"Mongolia\",\n MS: \"Montserrat\",\n MA: \"Morocco\",\n MZ: \"Mozambique\",\n MM: \"Myanmar\",\n NA: \"Namibia\",\n NR: \"Nauru\",\n NP: \"Nepal\",\n NL: \"Netherlands\",\n NC: \"New Caledonia\",\n NZ: \"New Zealand\",\n NI: \"Nicaragua\",\n NE: \"Niger\",\n NG: \"Nigeria\",\n NU: \"Niue\",\n NF: \"Norfolk Island\",\n MK: \"Macedonia\",\n MP: \"Northern Mariana Islands\",\n NO: \"Norway\",\n OM: \"Oman\",\n PK: \"Pakistan\",\n PW: \"Palau\",\n PS: \"Palestine\",\n PA: \"Panama\",\n PG: \"Papua New Guinea\",\n PY: \"Paraguay\",\n PE: \"Peru\",\n PH: \"Philippines\",\n PN: \"Pitcairn\",\n PL: \"Poland\",\n PT: \"Portugal\",\n PR: \"Puerto Rico\",\n QA: \"Qatar\",\n RE: \"Reunion\",\n RO: \"Romania\",\n RU: \"Russia\",\n RW: \"Rwanda\",\n SH: \"Saint Helena\",\n KN: \"Saint Kitts and Nevis\",\n LC: \"Saint Lucia\",\n PM: \"Saint Pierre and Miquelon\",\n VC: \"Saint Vincent and the Grenadines\",\n WS: \"Samoa\",\n SM: \"San Marino\",\n ST: \"Sao Tome and Principe\",\n SA: \"Saudi Arabia\",\n SN: \"Senegal\",\n SC: \"Seychelles\",\n SL: \"Sierra Leone\",\n SG: \"Singapore\",\n SK: \"Slovakia\",\n SI: \"Slovenia\",\n SB: \"Solomon Islands\",\n SO: \"Somalia\",\n ZA: \"South Africa\",\n GS: \"South Georgia and the South Sandwich Islands\",\n ES: \"Spain\",\n LK: \"Sri Lanka\",\n SD: \"Sudan\",\n SR: \"Suriname\",\n SJ: \"Svalbard and Jan Mayen\",\n SZ: \"Eswatini\",\n SE: \"Sweden\",\n CH: \"Switzerland\",\n SY: \"Syrian Arab Republic\",\n TW: \"Taiwan\",\n TJ: \"Tajikistan\",\n TZ: \"Tanzania\",\n TH: \"Thailand\",\n TL: \"Timor-Leste\",\n TG: \"Togo\",\n TK: \"Tokelau\",\n TO: \"Tonga\",\n TT: \"Trinidad and Tobago\",\n TN: \"Tunisia\",\n TR: \"Turkey\",\n TM: \"Turkmenistan\",\n TC: \"Turks and Caicos Islands\",\n TV: \"Tuvalu\",\n UG: \"Uganda\",\n UA: \"Ukraine\",\n AE: \"United Arab Emirates\",\n GB: \"United Kingdom\",\n US: \"United States\",\n UM: \"United States Minor Outlying Islands\",\n UY: \"Uruguay\",\n UZ: \"Uzbekistan\",\n VU: \"Vanuatu\",\n VE: \"Venezuela\",\n VN: \"Vietnam\",\n VG: \"Virgin Islands, British\",\n VI: \"Virgin Islands, U.S.\",\n WF: \"Wallis and Futuna\",\n EH: \"Western Sahara\",\n YE: \"Yemen\",\n ZM: \"Zambia\",\n ZW: \"Zimbabwe\",\n AX: \"Åland Islands\",\n BQ: \"Bonaire, Sint Eustatius and Saba\",\n CW: \"Curaçao\",\n GG: \"Guernsey\",\n IM: \"Isle of Man\",\n JE: \"Jersey\",\n ME: \"Montenegro\",\n BL: \"Saint Barthélemy\",\n MF: \"Saint Martin (French part)\",\n RS: \"Serbia\",\n SX: \"Sint Maarten (Dutch part)\",\n SS: \"South Sudan\",\n XK: \"Kosovo\",\n};\n\n/**\n * Array of all ISO 3166-1 alpha-2 country codes\n * Useful for iteration, validation, and type checking\n *\n * @example\n * ```ts\n * import { COUNTRY_CODES } from '@kumix/utils';\n *\n * // Validate user input\n * const isValidCountryCode = (code: string) => COUNTRY_CODES.includes(code);\n *\n * // Create a filter for countries\n * const countryFilters = COUNTRY_CODES.map(code => ({\n * id: code,\n * name: COUNTRIES[code],\n * selected: false\n * }));\n *\n * // Type safety for country code parameters\n * function getCountryData(countryCode: typeof COUNTRY_CODES[number]) {\n * // Function implementation...\n * }\n * ```\n */\nexport const COUNTRY_CODES = Object.keys(COUNTRIES) as [string, ...string[]];\n\n/**\n * Array of ISO 3166-1 alpha-2 country codes for European Union member states\n * Used for EU-specific functionality like GDPR compliance, VAT calculations, etc.\n *\n * @example\n * ```ts\n * import { EU_COUNTRY_CODES, COUNTRIES } from '@kumix/utils';\n *\n * // Check if a country is in the EU\n * const isEUCountry = (countryCode: string) => EU_COUNTRY_CODES.includes(countryCode);\n *\n * // Get list of EU country names\n * const euCountryNames = EU_COUNTRY_CODES.map(code => COUNTRIES[code]);\n *\n * // Filter users from EU countries\n * const euUsers = users.filter(user => EU_COUNTRY_CODES.includes(user.countryCode));\n *\n * // Apply EU-specific logic\n * function applyVAT(price: number, countryCode: string) {\n * if (EU_COUNTRY_CODES.includes(countryCode)) {\n * // Apply EU VAT rules\n * return price * 1.2; // Example VAT rate\n * }\n * return price;\n * }\n * ```\n */\n// EU member states (2020 onwards). The United Kingdom (GB) left the EU in\n// January 2020 (Brexit) and is intentionally excluded. Any EU-specific logic\n// (VAT/GDPR gating) requires this list to be accurate.\nexport const EU_COUNTRY_CODES = [\n \"AT\",\n \"BE\",\n \"BG\",\n \"HR\",\n \"CY\",\n \"CZ\",\n \"DK\",\n \"EE\",\n \"FI\",\n \"FR\",\n \"DE\",\n \"GR\",\n \"HU\",\n \"IE\",\n \"IT\",\n \"LV\",\n \"LT\",\n \"LU\",\n \"MT\",\n \"NL\",\n \"PL\",\n \"PT\",\n \"RO\",\n \"SK\",\n \"SI\",\n \"ES\",\n \"SE\",\n];\n","/**\n * Country Phone Codes\n * Provides mapping between country codes and their international calling codes\n */\n\n/**\n * Object mapping ISO 3166-1 alpha-2 country codes to their international calling codes\n * Used for phone number formatting, validation, and international dialing\n *\n * @example\n * ```ts\n * import { COUNTRY_PHONE_CODES } from '@kumix/utils';\n *\n * // Get phone code from country code\n * const usPhoneCode = COUNTRY_PHONE_CODES['US']; // 1\n *\n * // Format a phone number with international code\n * function formatInternationalPhone(countryCode: string, phoneNumber: string) {\n * const phoneCode = COUNTRY_PHONE_CODES[countryCode];\n * return `+${phoneCode} ${phoneNumber}`;\n * }\n *\n * // Create a phone input with country code selector\n * const phoneOptions = Object.entries(COUNTRY_PHONE_CODES).map(([code, phoneCode]) => ({\n * value: code,\n * label: `${code} (+${phoneCode})`,\n * }));\n *\n * // Note: Some countries share the same phone code (e.g., US and Canada both use +1)\n * ```\n */\nexport const COUNTRY_PHONE_CODES: { [key: string]: number } = {\n AF: 93,\n AL: 355,\n DZ: 213,\n AS: 1,\n AD: 376,\n AO: 244,\n AI: 1,\n AQ: 672,\n AG: 1,\n AR: 54,\n AM: 374,\n AW: 297,\n AU: 61,\n AT: 43,\n AZ: 994,\n BS: 1,\n BH: 973,\n BD: 880,\n BB: 1,\n BY: 375,\n BE: 32,\n BZ: 501,\n BJ: 229,\n BM: 1,\n BT: 975,\n BO: 591,\n BA: 387,\n BW: 267,\n BR: 55,\n IO: 246,\n BN: 673,\n BG: 359,\n BF: 226,\n BI: 257,\n KH: 855,\n CM: 237,\n CA: 1,\n CV: 238,\n KY: 1,\n CF: 236,\n TD: 235,\n CL: 56,\n CN: 86,\n CX: 61,\n CC: 61,\n CO: 57,\n KM: 269,\n CG: 242,\n CD: 243,\n CK: 682,\n CR: 506,\n CI: 225,\n HR: 385,\n CU: 53,\n CY: 357,\n CZ: 420,\n DK: 45,\n DJ: 253,\n DM: 1,\n DO: 1,\n EC: 593,\n EG: 20,\n SV: 503,\n GQ: 240,\n ER: 291,\n EE: 372,\n ET: 251,\n FK: 500,\n FO: 298,\n FJ: 679,\n FI: 358,\n FR: 33,\n GF: 594,\n PF: 689,\n GA: 241,\n GM: 220,\n GE: 995,\n DE: 49,\n GH: 233,\n GI: 350,\n GR: 30,\n GL: 299,\n GD: 1,\n GP: 590,\n GU: 1,\n GT: 502,\n GN: 224,\n GW: 245,\n GY: 592,\n HT: 509,\n VA: 379,\n HN: 504,\n HK: 852,\n HU: 36,\n IS: 354,\n IN: 91,\n ID: 62,\n IR: 98,\n IQ: 964,\n IE: 353,\n IL: 972,\n IT: 39,\n JM: 1,\n JP: 81,\n JO: 962,\n KZ: 7,\n KE: 254,\n KI: 686,\n KP: 850,\n KR: 82,\n KW: 965,\n KG: 996,\n LA: 856,\n LV: 371,\n LB: 961,\n LS: 266,\n LR: 231,\n LY: 218,\n LI: 423,\n LT: 370,\n LU: 352,\n MO: 853,\n MG: 261,\n MW: 265,\n MY: 60,\n MV: 960,\n ML: 223,\n MT: 356,\n MH: 692,\n MQ: 596,\n MR: 222,\n MU: 230,\n YT: 262,\n MX: 52,\n FM: 691,\n MD: 373,\n MC: 377,\n MN: 976,\n MS: 1,\n MA: 212,\n MZ: 258,\n MM: 95,\n NA: 264,\n NR: 674,\n NP: 977,\n NL: 31,\n NC: 687,\n NZ: 64,\n NI: 505,\n NE: 227,\n NG: 234,\n NU: 683,\n NF: 672,\n MK: 389,\n MP: 1,\n NO: 47,\n OM: 968,\n PK: 92,\n PW: 680,\n PS: 970,\n PA: 507,\n PG: 675,\n PY: 595,\n PE: 51,\n PH: 63,\n PN: 64,\n PL: 48,\n PT: 351,\n PR: 1,\n QA: 974,\n RE: 262,\n RO: 40,\n RU: 7,\n RW: 250,\n SH: 290,\n KN: 1,\n LC: 1,\n PM: 508,\n VC: 1,\n WS: 685,\n SM: 378,\n ST: 239,\n SA: 966,\n SN: 221,\n SC: 248,\n SL: 232,\n SG: 65,\n SK: 421,\n SI: 386,\n SB: 677,\n SO: 252,\n ZA: 27,\n ES: 34,\n LK: 94,\n SD: 249,\n SR: 597,\n SZ: 268,\n SE: 46,\n CH: 41,\n SY: 963,\n TW: 886,\n TJ: 992,\n TZ: 255,\n TH: 66,\n TL: 670,\n TG: 228,\n TK: 690,\n TO: 676,\n TT: 1,\n TN: 216,\n TR: 90,\n TM: 993,\n TC: 1,\n TV: 688,\n UG: 256,\n UA: 380,\n AE: 971,\n GB: 44,\n US: 1,\n UY: 598,\n UZ: 998,\n VU: 678,\n VE: 58,\n VN: 84,\n VG: 1,\n VI: 1,\n WF: 681,\n EH: 212,\n YE: 967,\n ZM: 260,\n ZW: 263,\n AX: 358,\n BQ: 599,\n CW: 599,\n GG: 44,\n IM: 44,\n JE: 44,\n ME: 382,\n BL: 590,\n MF: 590,\n RS: 381,\n SX: 1,\n SS: 211,\n XK: 383,\n // BV: null,\n // TF: null,\n // HM: null,\n // GS: null,\n // SJ: null,\n // UM: null,\n};\n","/**\n * Region Constants\n * Provides mapping between region/state/province codes and their names\n */\n\n/**\n * Object mapping region codes to their full names for countries worldwide\n * Uses ISO 3166-2 subdivision codes as keys\n *\n * @example\n * ```ts\n * import { REGIONS } from '@kumix/utils';\n *\n * // Get region name from code\n * const regionName = REGIONS['US-CA']; // 'California'\n *\n * // Check if a code is a valid region\n * const isValidRegion = 'CA-ON' in REGIONS; // true for Ontario, Canada\n *\n * // Get regions for a specific country\n * const usRegions = Object.entries(REGIONS)\n * .filter(([code]) => code.startsWith('US-'))\n * .map(([code, name]) => ({\n * value: code,\n * label: name\n * }));\n *\n * // Display region dropdown based on selected country\n * function getRegionsForCountry(countryCode: string) {\n * return Object.entries(REGIONS)\n * .filter(([code]) => code.startsWith(`${countryCode}-`))\n * .map(([code, name]) => ({\n * value: code,\n * label: name\n * }));\n * }\n * ```\n */\nexport const REGIONS: { [key: string]: string } = {\n \"AF-BDS\": \"Badakhshān\",\n \"AF-BDG\": \"Bādghīs\",\n \"AF-BGL\": \"Baghlān\",\n \"AF-BAL\": \"Balkh\",\n \"AF-BAM\": \"Bāmyān\",\n \"AF-DAY\": \"Dāykundī\",\n \"AF-FRA\": \"Farāh\",\n \"AF-FYB\": \"Fāryāb\",\n \"AF-GHA\": \"Ghaznī\",\n \"AF-GHO\": \"Ghōr\",\n \"AF-HEL\": \"Helmand\",\n \"AF-HER\": \"Herāt\",\n \"AF-JOW\": \"Jowzjān\",\n \"AF-KAB\": \"Kābul\",\n \"AF-KAN\": \"Kandahār\",\n \"AF-KAP\": \"Kāpīsā\",\n \"AF-KHO\": \"Khōst\",\n \"AF-KNR\": \"Kunaṟ\",\n \"AF-KDZ\": \"Kunduz\",\n \"AF-LAG\": \"Laghmān\",\n \"AF-LOG\": \"Lōgar\",\n \"AF-NAN\": \"Nangarhār\",\n \"AF-NIM\": \"Nīmrōz\",\n \"AF-NUR\": \"Nūristān\",\n \"AF-PKA\": \"Paktīkā\",\n \"AF-PIA\": \"Paktiyā\",\n \"AF-PAN\": \"Panjshayr\",\n \"AF-PAR\": \"Parwān\",\n \"AF-SAM\": \"Samangān\",\n \"AF-SAR\": \"Sar-e Pul\",\n \"AF-TAK\": \"Takhār\",\n \"AF-URU\": \"Uruzgān\",\n \"AF-WAR\": \"Wardak\",\n \"AF-ZAB\": \"Zābul\",\n \"AL-01\": \"Berat\",\n \"AL-09\": \"Dibër\",\n \"AL-02\": \"Durrës\",\n \"AL-03\": \"Elbasan\",\n \"AL-04\": \"Fier\",\n \"AL-05\": \"Gjirokastër\",\n \"AL-06\": \"Korçë\",\n \"AL-07\": \"Kukës\",\n \"AL-08\": \"Lezhë\",\n \"AL-10\": \"Shkodër\",\n \"AL-11\": \"Tiranë\",\n \"AL-12\": \"Vlorë\",\n \"DZ-01\": \"Adrar\",\n \"DZ-44\": \"Aïn Defla\",\n \"DZ-46\": \"Aïn Témouchent\",\n \"DZ-16\": \"Alger\",\n \"DZ-23\": \"Annaba\",\n \"DZ-05\": \"Batna\",\n \"DZ-08\": \"Béchar\",\n \"DZ-06\": \"Béjaïa\",\n \"DZ-52\": \"Béni Abbès\",\n \"DZ-07\": \"Biskra\",\n \"DZ-09\": \"Blida\",\n \"DZ-50\": \"Bordj Badji Mokhtar\",\n \"DZ-34\": \"Bordj Bou Arréridj\",\n \"DZ-10\": \"Bouira\",\n \"DZ-35\": \"Boumerdès\",\n \"DZ-02\": \"Chlef\",\n \"DZ-25\": \"Constantine\",\n \"DZ-56\": \"Djanet\",\n \"DZ-17\": \"Djelfa\",\n \"DZ-32\": \"El Bayadh\",\n \"DZ-57\": \"El Meghaier\",\n \"DZ-58\": \"El Meniaa\",\n \"DZ-39\": \"El Oued\",\n \"DZ-36\": \"El Tarf\",\n \"DZ-47\": \"Ghardaïa\",\n \"DZ-24\": \"Guelma\",\n \"DZ-33\": \"Illizi\",\n \"DZ-54\": \"In Guezzam\",\n \"DZ-53\": \"In Salah\",\n \"DZ-18\": \"Jijel\",\n \"DZ-40\": \"Khenchela\",\n \"DZ-03\": \"Laghouat\",\n \"DZ-28\": \"M'sila\",\n \"DZ-29\": \"Mascara\",\n \"DZ-26\": \"Médéa\",\n \"DZ-43\": \"Mila\",\n \"DZ-27\": \"Mostaganem\",\n \"DZ-45\": \"Naama\",\n \"DZ-31\": \"Oran\",\n \"DZ-30\": \"Ouargla\",\n \"DZ-51\": \"Ouled Djellal\",\n \"DZ-04\": \"Oum el Bouaghi\",\n \"DZ-48\": \"Relizane\",\n \"DZ-20\": \"Saïda\",\n \"DZ-19\": \"Sétif\",\n \"DZ-22\": \"Sidi Bel Abbès\",\n \"DZ-21\": \"Skikda\",\n \"DZ-41\": \"Souk Ahras\",\n \"DZ-11\": \"Tamanrasset\",\n \"DZ-12\": \"Tébessa\",\n \"DZ-14\": \"Tiaret\",\n \"DZ-49\": \"Timimoun\",\n \"DZ-37\": \"Tindouf\",\n \"DZ-42\": \"Tipaza\",\n \"DZ-38\": \"Tissemsilt\",\n \"DZ-15\": \"Tizi Ouzou\",\n \"DZ-13\": \"Tlemcen\",\n \"DZ-55\": \"Touggourt\",\n \"AD-07\": \"Andorra la Vella\",\n \"AD-02\": \"Canillo\",\n \"AD-03\": \"Encamp\",\n \"AD-08\": \"Escaldes-Engordany\",\n \"AD-04\": \"La Massana\",\n \"AD-05\": \"Ordino\",\n \"AD-06\": \"Sant Julià de Lòria\",\n \"AO-BGO\": \"Bengo\",\n \"AO-BGU\": \"Benguela\",\n \"AO-BIE\": \"Bié\",\n \"AO-CAB\": \"Cabinda\",\n \"AO-CCU\": \"Cuando Cubango\",\n \"AO-CNO\": \"Cuanza-Norte\",\n \"AO-CUS\": \"Cuanza-Sul\",\n \"AO-CNN\": \"Cunene\",\n \"AO-HUA\": \"Huambo\",\n \"AO-HUI\": \"Huíla\",\n \"AO-LUA\": \"Luanda\",\n \"AO-LNO\": \"Lunda-Norte\",\n \"AO-LSU\": \"Lunda-Sul\",\n \"AO-MAL\": \"Malange\",\n \"AO-MOX\": \"Moxico\",\n \"AO-NAM\": \"Namibe\",\n \"AO-UIG\": \"Uíge\",\n \"AO-ZAI\": \"Zaire\",\n \"AG-03\": \"Saint George\",\n \"AG-04\": \"Saint John\",\n \"AG-05\": \"Saint Mary\",\n \"AG-06\": \"Saint Paul\",\n \"AG-07\": \"Saint Peter\",\n \"AG-08\": \"Saint Philip\",\n \"AG-10\": \"Barbuda\",\n \"AG-11\": \"Redonda\",\n \"AR-B\": \"Buenos Aires\",\n \"AR-K\": \"Catamarca\",\n \"AR-H\": \"Chaco\",\n \"AR-U\": \"Chubut\",\n \"AR-C\": \"Ciudad Autónoma de Buenos Aires\",\n \"AR-X\": \"Córdoba\",\n \"AR-W\": \"Corrientes\",\n \"AR-E\": \"Entre Ríos\",\n \"AR-P\": \"Formosa\",\n \"AR-Y\": \"Jujuy\",\n \"AR-L\": \"La Pampa\",\n \"AR-F\": \"La Rioja\",\n \"AR-M\": \"Mendoza\",\n \"AR-N\": \"Misiones\",\n \"AR-Q\": \"Neuquén\",\n \"AR-R\": \"Río Negro\",\n \"AR-A\": \"Salta\",\n \"AR-J\": \"San Juan\",\n \"AR-D\": \"San Luis\",\n \"AR-Z\": \"Santa Cruz\",\n \"AR-S\": \"Santa Fe\",\n \"AR-G\": \"Santiago del Estero\",\n \"AR-V\": \"Tierra del Fuego\",\n \"AR-T\": \"Tucumán\",\n \"AM-AG\": \"Aragac̣otn\",\n \"AM-AR\": \"Ararat\",\n \"AM-AV\": \"Armavir\",\n \"AM-ER\": \"Erevan\",\n \"AM-GR\": \"Geġark'unik'\",\n \"AM-KT\": \"Kotayk'\",\n \"AM-LO\": \"Loṙi\",\n \"AM-SH\": \"Širak\",\n \"AM-SU\": \"Syunik'\",\n \"AM-TV\": \"Tavuš\",\n \"AM-VD\": \"Vayoć Jor\",\n \"AU-NSW\": \"New South Wales\",\n \"AU-QLD\": \"Queensland\",\n \"AU-SA\": \"South Australia\",\n \"AU-TAS\": \"Tasmania\",\n \"AU-VIC\": \"Victoria\",\n \"AU-WA\": \"Western Australia\",\n \"AU-ACT\": \"Australian Capital Territory\",\n \"AU-NT\": \"Northern Territory\",\n \"AT-1\": \"Burgenland\",\n \"AT-2\": \"Kärnten\",\n \"AT-3\": \"Niederösterreich\",\n \"AT-4\": \"Oberösterreich\",\n \"AT-5\": \"Salzburg\",\n \"AT-6\": \"Steiermark\",\n \"AT-7\": \"Tirol\",\n \"AT-8\": \"Vorarlberg\",\n \"AT-9\": \"Wien\",\n \"AZ-NX\": \"Naxçıvan\",\n \"BS-AK\": \"Acklins\",\n \"BS-BY\": \"Berry Islands\",\n \"BS-BI\": \"Bimini\",\n \"BS-BP\": \"Black Point\",\n \"BS-CI\": \"Cat Island\",\n \"BS-CO\": \"Central Abaco\",\n \"BS-CS\": \"Central Andros\",\n \"BS-CE\": \"Central Eleuthera\",\n \"BS-FP\": \"City of Freeport\",\n \"BS-CK\": \"Crooked Island and Long Cay\",\n \"BS-EG\": \"East Grand Bahama\",\n \"BS-EX\": \"Exuma\",\n \"BS-GC\": \"Grand Cay\",\n \"BS-HI\": \"Harbour Island\",\n \"BS-HT\": \"Hope Town\",\n \"BS-IN\": \"Inagua\",\n \"BS-LI\": \"Long Island\",\n \"BS-MC\": \"Mangrove Cay\",\n \"BS-MG\": \"Mayaguana\",\n \"BS-MI\": \"Moore's Island\",\n \"BS-NP\": \"New Providence\",\n \"BS-NO\": \"North Abaco\",\n \"BS-NS\": \"North Andros\",\n \"BS-NE\": \"North Eleuthera\",\n \"BS-RI\": \"Ragged Island\",\n \"BS-RC\": \"Rum Cay\",\n \"BS-SS\": \"San Salvador\",\n \"BS-SO\": \"South Abaco\",\n \"BS-SA\": \"South Andros\",\n \"BS-SE\": \"South Eleuthera\",\n \"BS-SW\": \"Spanish Wells\",\n \"BS-WG\": \"West Grand Bahama\",\n \"BH-13\": \"Al ‘Āşimah\",\n \"BH-14\": \"Al Janūbīyah\",\n \"BH-15\": \"Al Muḩarraq\",\n \"BH-17\": \"Ash Shamālīyah\",\n \"BD-A\": \"Barishal\",\n \"BD-B\": \"Chattogram\",\n \"BD-C\": \"Dhaka\",\n \"BD-D\": \"Khulna\",\n \"BD-H\": \"Mymensingh\",\n \"BD-E\": \"Rajshahi\",\n \"BD-F\": \"Rangpur\",\n \"BD-G\": \"Sylhet\",\n \"BB-01\": \"Christ Church\",\n \"BB-02\": \"Saint Andrew\",\n \"BB-03\": \"Saint George\",\n \"BB-04\": \"Saint James\",\n \"BB-05\": \"Saint John\",\n \"BB-06\": \"Saint Joseph\",\n \"BB-07\": \"Saint Lucy\",\n \"BB-08\": \"Saint Michael\",\n \"BB-09\": \"Saint Peter\",\n \"BB-10\": \"Saint Philip\",\n \"BB-11\": \"Saint Thomas\",\n \"BY-BR\": \"Brestskaya voblasts'\",\n \"BY-HO\": \"Homyel'skaya voblasts'\",\n \"BY-HM\": \"Horad Minsk\",\n \"BY-HR\": \"Hrodzyenskaya voblasts'\",\n \"BY-MA\": \"Mahilyowskaya voblasts'\",\n \"BY-MI\": \"Minskaya voblasts'\",\n \"BY-VI\": \"Vitsyebskaya voblasts'\",\n \"BE-BRU\": \"Brussels Hoofdstedelijk Gewest\",\n \"BE-VLG\": \"Vlaams Gewest\",\n \"BE-WAL\": \"Waals Gewest\",\n \"BZ-BZ\": \"Belize\",\n \"BZ-CY\": \"Cayo\",\n \"BZ-CZL\": \"Corozal\",\n \"BZ-OW\": \"Orange Walk\",\n \"BZ-SC\": \"Stann Creek\",\n \"BZ-TOL\": \"Toledo\",\n \"BJ-AL\": \"Alibori\",\n \"BJ-AK\": \"Atacora\",\n \"BJ-AQ\": \"Atlantique\",\n \"BJ-BO\": \"Borgou\",\n \"BJ-CO\": \"Collines\",\n \"BJ-KO\": \"Couffo\",\n \"BJ-DO\": \"Donga\",\n \"BJ-LI\": \"Littoral\",\n \"BJ-MO\": \"Mono\",\n \"BJ-OU\": \"Ouémé\",\n \"BJ-PL\": \"Plateau\",\n \"BJ-ZO\": \"Zou\",\n \"BT-33\": \"Bumthang\",\n \"BT-12\": \"Chhukha\",\n \"BT-22\": \"Dagana\",\n \"BT-GA\": \"Gasa\",\n \"BT-13\": \"Haa\",\n \"BT-44\": \"Lhuentse\",\n \"BT-42\": \"Monggar\",\n \"BT-11\": \"Paro\",\n \"BT-43\": \"Pema Gatshel\",\n \"BT-23\": \"Punakha\",\n \"BT-45\": \"Samdrup Jongkhar\",\n \"BT-14\": \"Samtse\",\n \"BT-31\": \"Sarpang\",\n \"BT-15\": \"Thimphu\",\n \"BT-41\": \"Trashigang\",\n \"BT-TY\": \"Trashi Yangtse\",\n \"BT-32\": \"Trongsa\",\n \"BT-21\": \"Tsirang\",\n \"BT-24\": \"Wangdue Phodrang\",\n \"BT-34\": \"Zhemgang\",\n \"BO-C\": \"Cochabamba\",\n \"BO-H\": \"Chuquisaca\",\n \"BO-B\": \"El Beni\",\n \"BO-L\": \"La Paz\",\n \"BO-O\": \"Oruro\",\n \"BO-N\": \"Pando\",\n \"BO-P\": \"Potosí\",\n \"BO-S\": \"Santa Cruz\",\n \"BO-T\": \"Tarija\",\n \"BA-BIH\": \"Federacija Bosne i Hercegovine\",\n \"BA-SRP\": \"Republika Srpska\",\n \"BA-BRC\": \"Brčko distrikt\",\n \"BW-CE\": \"Central\",\n \"BW-CH\": \"Chobe\",\n \"BW-FR\": \"Francistown\",\n \"BW-GA\": \"Gaborone\",\n \"BW-GH\": \"Ghanzi\",\n \"BW-JW\": \"Jwaneng\",\n \"BW-KG\": \"Kgalagadi\",\n \"BW-KL\": \"Kgatleng\",\n \"BW-KW\": \"Kweneng\",\n \"BW-LO\": \"Lobatse\",\n \"BW-NE\": \"North East\",\n \"BW-NW\": \"North West\",\n \"BW-SP\": \"Selibe Phikwe\",\n \"BW-SE\": \"South East\",\n \"BW-SO\": \"Southern\",\n \"BW-ST\": \"Sowa Town\",\n \"BR-AC\": \"Acre\",\n \"BR-AL\": \"Alagoas\",\n \"BR-AP\": \"Amapá\",\n \"BR-AM\": \"Amazonas\",\n \"BR-BA\": \"Bahia\",\n \"BR-CE\": \"Ceará\",\n \"BR-DF\": \"Distrito Federal\",\n \"BR-ES\": \"Espírito Santo\",\n \"BR-GO\": \"Goiás\",\n \"BR-MA\": \"Maranhão\",\n \"BR-MT\": \"Mato Grosso\",\n \"BR-MS\": \"Mato Grosso do Sul\",\n \"BR-MG\": \"Minas Gerais\",\n \"BR-PA\": \"Pará\",\n \"BR-PB\": \"Paraíba\",\n \"BR-PR\": \"Paraná\",\n \"BR-PE\": \"Pernambuco\",\n \"BR-PI\": \"Piauí\",\n \"BR-RJ\": \"Rio de Janeiro\",\n \"BR-RN\": \"Rio Grande do Norte\",\n \"BR-RS\": \"Rio Grande do Sul\",\n \"BR-RO\": \"Rondônia\",\n \"BR-RR\": \"Roraima\",\n \"BR-SC\": \"Santa Catarina\",\n \"BR-SP\": \"São Paulo\",\n \"BR-SE\": \"Sergipe\",\n \"BR-TO\": \"Tocantins\",\n \"BN-BE\": \"Belait\",\n \"BN-BM\": \"Brunei-Muara\",\n \"BN-TE\": \"Temburong\",\n \"BN-TU\": \"Tutong\",\n \"BG-01\": \"Blagoevgrad\",\n \"BG-02\": \"Burgas\",\n \"BG-08\": \"Dobrich\",\n \"BG-07\": \"Gabrovo\",\n \"BG-26\": \"Haskovo\",\n \"BG-09\": \"Kardzhali\",\n \"BG-10\": \"Kyustendil\",\n \"BG-11\": \"Lovech\",\n \"BG-12\": \"Montana\",\n \"BG-13\": \"Pazardzhik\",\n \"BG-14\": \"Pernik\",\n \"BG-15\": \"Pleven\",\n \"BG-16\": \"Plovdiv\",\n \"BG-17\": \"Razgrad\",\n \"BG-18\": \"Ruse\",\n \"BG-27\": \"Shumen\",\n \"BG-19\": \"Silistra\",\n \"BG-20\": \"Sliven\",\n \"BG-21\": \"Smolyan\",\n \"BG-23\": \"Sofia\",\n \"BG-22\": \"Sofia (stolitsa)\",\n \"BG-24\": \"Stara Zagora\",\n \"BG-25\": \"Targovishte\",\n \"BG-03\": \"Varna\",\n \"BG-04\": \"Veliko Tarnovo\",\n \"BG-05\": \"Vidin\",\n \"BG-06\": \"Vratsa\",\n \"BG-28\": \"Yambol\",\n \"BF-01\": \"Boucle du Mouhoun\",\n \"BF-02\": \"Cascades\",\n \"BF-03\": \"Centre\",\n \"BF-04\": \"Centre-Est\",\n \"BF-05\": \"Centre-Nord\",\n \"BF-06\": \"Centre-Ouest\",\n \"BF-07\": \"Centre-Sud\",\n \"BF-08\": \"Est\",\n \"BF-09\": \"Hauts-Bassins\",\n \"BF-10\": \"Nord\",\n \"BF-11\": \"Plateau-Central\",\n \"BF-12\": \"Sahel\",\n \"BF-13\": \"Sud-Ouest\",\n \"BI-BB\": \"Bubanza\",\n \"BI-BM\": \"Bujumbura Mairie\",\n \"BI-BL\": \"Bujumbura Rural\",\n \"BI-BR\": \"Bururi\",\n \"BI-CA\": \"Cankuzo\",\n \"BI-CI\": \"Cibitoke\",\n \"BI-GI\": \"Gitega\",\n \"BI-KR\": \"Karuzi\",\n \"BI-KY\": \"Kayanza\",\n \"BI-KI\": \"Kirundo\",\n \"BI-MA\": \"Makamba\",\n \"BI-MU\": \"Muramvya\",\n \"BI-MY\": \"Muyinga\",\n \"BI-MW\": \"Mwaro\",\n \"BI-NG\": \"Ngozi\",\n \"BI-RM\": \"Rumonge\",\n \"BI-RT\": \"Rutana\",\n \"BI-RY\": \"Ruyigi\",\n \"KH-2\": \"Baat Dambang\",\n \"KH-1\": \"Banteay Mean Choăy\",\n \"KH-23\": \"Kaeb\",\n \"KH-3\": \"Kampong Chaam\",\n \"KH-4\": \"Kampong Chhnang\",\n \"KH-5\": \"Kampong Spueu\",\n \"KH-6\": \"Kampong Thum\",\n \"KH-7\": \"Kampot\",\n \"KH-8\": \"Kandaal\",\n \"KH-9\": \"Kaoh Kong\",\n \"KH-10\": \"Kracheh\",\n \"KH-11\": \"Mondol Kiri\",\n \"KH-22\": \"Otdar Mean Chey\",\n \"KH-24\": \"Pailin\",\n \"KH-12\": \"Phnom Penh\",\n \"KH-15\": \"Pousaat\",\n \"KH-18\": \"Preah Sihanouk\",\n \"KH-13\": \"Preah Vihear\",\n \"KH-14\": \"Prey Veaeng\",\n \"KH-16\": \"Rotanak Kiri\",\n \"KH-17\": \"Siem Reab\",\n \"KH-19\": \"Stueng Traeng\",\n \"KH-20\": \"Svaay Rieng\",\n \"KH-21\": \"Taakaev\",\n \"KH-25\": \"Tbong Khmum\",\n \"CM-AD\": \"Adamaoua\",\n \"CM-CE\": \"Centre\",\n \"CM-ES\": \"East\",\n \"CM-EN\": \"Far North\",\n \"CM-LT\": \"Littoral\",\n \"CM-NO\": \"North\",\n \"CM-NW\": \"North-West\",\n \"CM-SU\": \"South\",\n \"CM-SW\": \"South-West\",\n \"CM-OU\": \"West\",\n \"CA-AB\": \"Alberta\",\n \"CA-BC\": \"British Columbia\",\n \"CA-MB\": \"Manitoba\",\n \"CA-NB\": \"New Brunswick\",\n \"CA-NL\": \"Newfoundland and Labrador\",\n \"CA-NT\": \"Northwest Territories\",\n \"CA-NS\": \"Nova Scotia\",\n \"CA-NU\": \"Nunavut\",\n \"CA-ON\": \"Ontario\",\n \"CA-PE\": \"Prince Edward Island\",\n \"CA-QC\": \"Quebec\",\n \"CA-SK\": \"Saskatchewan\",\n \"CA-YT\": \"Yukon\",\n \"CV-B\": \"Ilhas de Barlavento\",\n \"CV-S\": \"Ilhas de Sotavento\",\n \"CF-BB\": \"Bamingui-Bangoran\",\n \"CF-BGF\": \"Bangui\",\n \"CF-BK\": \"Basse-Kotto\",\n \"CF-KB\": \"Gribingui\",\n \"CF-HM\": \"Haut-Mbomou\",\n \"CF-HK\": \"Haute-Kotto\",\n \"CF-HS\": \"Haute-Sangha / Mambéré-Kadéï\",\n \"CF-KG\": \"Kémo-Gribingui\",\n \"CF-LB\": \"Lobaye\",\n \"CF-MB\": \"Mbomou\",\n \"CF-NM\": \"Nana-Mambéré\",\n \"CF-MP\": \"Ombella-Mpoko\",\n \"CF-UK\": \"Ouaka\",\n \"CF-AC\": \"Ouham\",\n \"CF-OP\": \"Ouham-Pendé\",\n \"CF-SE\": \"Sangha\",\n \"CF-VK\": \"Vakaga\",\n \"TD-BG\": \"Baḩr al Ghazāl\",\n \"TD-BA\": \"Al Baţḩā’\",\n \"TD-BO\": \"Būrkū\",\n \"TD-CB\": \"Shārī Bāqirmī\",\n \"TD-EE\": \"Inīdī ash Sharqī\",\n \"TD-EO\": \"Inīdī al Gharbī\",\n \"TD-GR\": \"Qīrā\",\n \"TD-HL\": \"Ḩajjar Lamīs\",\n \"TD-KA\": \"Kānim\",\n \"TD-LC\": \"Al Buḩayrah\",\n \"TD-LO\": \"Lūghūn al Gharbī\",\n \"TD-LR\": \"Lūghūn ash Sharqī\",\n \"TD-MA\": \"Māndūl\",\n \"TD-ME\": \"Māyū Kībbī ash Sharqī\",\n \"TD-MO\": \"Māyū Kībbī al Gharbī\",\n \"TD-MC\": \"Shārī al Awsaţ\",\n \"TD-OD\": \"Waddāy\",\n \"TD-SA\": \"Salāmāt\",\n \"TD-SI\": \"Sīlā\",\n \"TD-TA\": \"Tānjīlī\",\n \"TD-TI\": \"Tibastī\",\n \"TD-ND\": \"Madīnat Injamīnā\",\n \"TD-WF\": \"Wādī Fīrā’\",\n \"CL-AI\": \"Aisén del General Carlos Ibañez del Campo\",\n \"CL-AN\": \"Antofagasta\",\n \"CL-AP\": \"Arica y Parinacota\",\n \"CL-AT\": \"Atacama\",\n \"CL-BI\": \"Biobío\",\n \"CL-CO\": \"Coquimbo\",\n \"CL-AR\": \"La Araucanía\",\n \"CL-LI\": \"Libertador General Bernardo O'Higgins\",\n \"CL-LL\": \"Los Lagos\",\n \"CL-LR\": \"Los Ríos\",\n \"CL-MA\": \"Magallanes\",\n \"CL-ML\": \"Maule\",\n \"CL-NB\": \"Ñuble\",\n \"CL-RM\": \"Región Metropolitana de Santiago\",\n \"CL-TA\": \"Tarapacá\",\n \"CL-VS\": \"Valparaíso\",\n \"CN-AH\": \"Anhui Sheng\",\n \"CN-BJ\": \"Beijing Shi\",\n \"CN-CQ\": \"Chongqing Shi\",\n \"CN-FJ\": \"Fujian Sheng\",\n \"CN-GS\": \"Gansu Sheng\",\n \"CN-GD\": \"Guangdong Sheng\",\n \"CN-GX\": \"Guangxi Zhuangzu Zizhiqu\",\n \"CN-GZ\": \"Guizhou Sheng\",\n \"CN-HI\": \"Hainan Sheng\",\n \"CN-HE\": \"Hebei Sheng\",\n \"CN-HL\": \"Heilongjiang Sheng\",\n \"CN-HA\": \"Henan Sheng\",\n \"CN-HK\": \"Hong Kong SARen\",\n \"CN-HB\": \"Hubei Sheng\",\n \"CN-HN\": \"Hunan Sheng\",\n \"CN-JS\": \"Jiangsu Sheng\",\n \"CN-JX\": \"Jiangxi Sheng\",\n \"CN-JL\": \"Jilin Sheng\",\n \"CN-LN\": \"Liaoning Sheng\",\n \"CN-MO\": \"Macao SARpt\",\n \"CN-NM\": \"Nei Mongol Zizhiqu\",\n \"CN-NX\": \"Ningxia Huizu Zizhiqu\",\n \"CN-QH\": \"Qinghai Sheng\",\n \"CN-SN\": \"Shaanxi Sheng\",\n \"CN-SD\": \"Shandong Sheng\",\n \"CN-SH\": \"Shanghai Shi\",\n \"CN-SX\": \"Shanxi Sheng\",\n \"CN-SC\": \"Sichuan Sheng\",\n \"CN-TW\": \"Taiwan Sheng\",\n \"CN-TJ\": \"Tianjin Shi\",\n \"CN-XJ\": \"Xinjiang Uygur Zizhiqu\",\n \"CN-XZ\": \"Xizang Zizhiqu\",\n \"CN-YN\": \"Yunnan Sheng\",\n \"CN-ZJ\": \"Zhejiang Sheng\",\n \"CO-AMA\": \"Amazonas\",\n \"CO-ANT\": \"Antioquia\",\n \"CO-ARA\": \"Arauca\",\n \"CO-ATL\": \"Atlántico\",\n \"CO-BOL\": \"Bolívar\",\n \"CO-BOY\": \"Boyacá\",\n \"CO-CAL\": \"Caldas\",\n \"CO-CAQ\": \"Caquetá\",\n \"CO-CAS\": \"Casanare\",\n \"CO-CAU\": \"Cauca\",\n \"CO-CES\": \"Cesar\",\n \"CO-COR\": \"Córdoba\",\n \"CO-CUN\": \"Cundinamarca\",\n \"CO-CHO\": \"Chocó\",\n \"CO-DC\": \"Distrito Capital de Bogotá\",\n \"CO-GUA\": \"Guainía\",\n \"CO-GUV\": \"Guaviare\",\n \"CO-HUI\": \"Huila\",\n \"CO-LAG\": \"La Guajira\",\n \"CO-MAG\": \"Magdalena\",\n \"CO-MET\": \"Meta\",\n \"CO-NAR\": \"Nariño\",\n \"CO-NSA\": \"Norte de Santander\",\n \"CO-PUT\": \"Putumayo\",\n \"CO-QUI\": \"Quindío\",\n \"CO-RIS\": \"Risaralda\",\n \"CO-SAP\": \"San Andrés\",\n \"CO-SAN\": \"Santander\",\n \"CO-SUC\": \"Sucre\",\n \"CO-TOL\": \"Tolima\",\n \"CO-VAC\": \"Valle del Cauca\",\n \"CO-VAU\": \"Vaupés\",\n \"CO-VID\": \"Vichada\",\n \"KM-G\": \"Grande Comore\",\n \"KM-A\": \"Anjouan\",\n \"KM-M\": \"Mohéli\",\n \"CG-11\": \"Bouenza\",\n \"CG-BZV\": \"Brazzaville\",\n \"CG-8\": \"Cuvette\",\n \"CG-15\": \"Cuvette-Ouest\",\n \"CG-5\": \"Kouilou\",\n \"CG-2\": \"Lékoumou\",\n \"CG-7\": \"Likouala\",\n \"CG-9\": \"Niari\",\n \"CG-14\": \"Plateaux\",\n \"CG-16\": \"Pointe-Noire\",\n \"CG-12\": \"Pool\",\n \"CG-13\": \"Sangha\",\n \"CD-BU\": \"Bas-Uélé\",\n \"CD-EQ\": \"Équateur\",\n \"CD-HK\": \"Haut-Katanga\",\n \"CD-HL\": \"Haut-Lomami\",\n \"CD-HU\": \"Haut-Uélé\",\n \"CD-IT\": \"Ituri\",\n \"CD-KS\": \"Kasaï\",\n \"CD-KC\": \"Kasaï Central\",\n \"CD-KE\": \"Kasaï Oriental\",\n \"CD-KN\": \"Kinshasa\",\n \"CD-BC\": \"Kongo Central\",\n \"CD-KG\": \"Kwango\",\n \"CD-KL\": \"Kwilu\",\n \"CD-LO\": \"Lomami\",\n \"CD-LU\": \"Lualaba\",\n \"CD-MN\": \"Mai-Ndombe\",\n \"CD-MA\": \"Maniema\",\n \"CD-MO\": \"Mongala\",\n \"CD-NK\": \"Nord-Kivu\",\n \"CD-NU\": \"Nord-Ubangi\",\n \"CD-SA\": \"Sankuru\",\n \"CD-SK\": \"Sud-Kivu\",\n \"CD-SU\": \"Sud-Ubangi\",\n \"CD-TA\": \"Tanganyika\",\n \"CD-TO\": \"Tshopo\",\n \"CD-TU\": \"Tshuapa\",\n \"CR-A\": \"Alajuela\",\n \"CR-C\": \"Cartago\",\n \"CR-G\": \"Guanacaste\",\n \"CR-H\": \"Heredia\",\n \"CR-L\": \"Limón\",\n \"CR-P\": \"Puntarenas\",\n \"CR-SJ\": \"San José\",\n \"CI-AB\": \"Abidjan\",\n \"CI-BS\": \"Bas-Sassandra\",\n \"CI-CM\": \"Comoé\",\n \"CI-DN\": \"Denguélé\",\n \"CI-GD\": \"Gôh-Djiboua\",\n \"CI-LC\": \"Lacs\",\n \"CI-LG\": \"Lagunes\",\n \"CI-MG\": \"Montagnes\",\n \"CI-SM\": \"Sassandra-Marahoué\",\n \"CI-SV\": \"Savanes\",\n \"CI-VB\": \"Vallée du Bandama\",\n \"CI-WR\": \"Woroba\",\n \"CI-YM\": \"Yamoussoukro\",\n \"CI-ZZ\": \"Zanzan\",\n \"HR-07\": \"Bjelovarsko-bilogorska županija\",\n \"HR-12\": \"Brodsko-posavska županija\",\n \"HR-19\": \"Dubrovačko-neretvanska županija\",\n \"HR-21\": \"Grad Zagreb\",\n \"HR-18\": \"Istarska županija\",\n \"HR-04\": \"Karlovačka županija\",\n \"HR-06\": \"Koprivničko-križevačka županija\",\n \"HR-02\": \"Krapinsko-zagorska županija\",\n \"HR-09\": \"Ličko-senjska županija\",\n \"HR-20\": \"Međimurska županija\",\n \"HR-14\": \"Osječko-baranjska županija\",\n \"HR-11\": \"Požeško-slavonska županija\",\n \"HR-08\": \"Primorsko-goranska županija\",\n \"HR-03\": \"Sisačko-moslavačka županija\",\n \"HR-17\": \"Splitsko-dalmatinska županija\",\n \"HR-15\": \"Šibensko-kninska županija\",\n \"HR-05\": \"Varaždinska županija\",\n \"HR-10\": \"Virovitičko-podravska županija\",\n \"HR-16\": \"Vukovarsko-srijemska županija\",\n \"HR-13\": \"Zadarska županija\",\n \"HR-01\": \"Zagrebačka županija\",\n \"CU-15\": \"Artemisa\",\n \"CU-09\": \"Camagüey\",\n \"CU-08\": \"Ciego de Ávila\",\n \"CU-06\": \"Cienfuegos\",\n \"CU-12\": \"Granma\",\n \"CU-14\": \"Guantánamo\",\n \"CU-11\": \"Holguín\",\n \"CU-03\": \"La Habana\",\n \"CU-10\": \"Las Tunas\",\n \"CU-04\": \"Matanzas\",\n \"CU-16\": \"Mayabeque\",\n \"CU-01\": \"Pinar del Río\",\n \"CU-07\": \"Sancti Spíritus\",\n \"CU-13\": \"Santiago de Cuba\",\n \"CU-05\": \"Villa Clara\",\n \"CU-99\": \"Isla de la Juventud\",\n \"CY-04\": \"Ammochostos\",\n \"CY-06\": \"Keryneia\",\n \"CY-03\": \"Larnaka\",\n \"CY-01\": \"Lefkosia\",\n \"CY-02\": \"Lemesos\",\n \"CY-05\": \"Pafos\",\n \"CZ-31\": \"Jihočeský kraj\",\n \"CZ-64\": \"Jihomoravský kraj\",\n \"CZ-41\": \"Karlovarský kraj\",\n \"CZ-52\": \"Královéhradecký kraj\",\n \"CZ-51\": \"Liberecký kraj\",\n \"CZ-80\": \"Moravskoslezský kraj\",\n \"CZ-71\": \"Olomoucký kraj\",\n \"CZ-53\": \"Pardubický kraj\",\n \"CZ-32\": \"Plzeňský kraj\",\n \"CZ-10\": \"Praha\",\n \"CZ-20\": \"Středočeský kraj\",\n \"CZ-42\": \"Ústecký kraj\",\n \"CZ-63\": \"Kraj Vysočina\",\n \"CZ-72\": \"Zlínský kraj\",\n \"DK-84\": \"Region Hovedstaden\",\n \"DK-82\": \"Region Midjylland\",\n \"DK-81\": \"Region Nordjylland\",\n \"DK-85\": \"Region Sjælland\",\n \"DK-83\": \"Region Syddanmark\",\n \"DJ-AS\": \"Ali Sabieh\",\n \"DJ-AR\": \"Arta\",\n \"DJ-DI\": \"Dikhil\",\n \"DJ-DJ\": \"Djibouti\",\n \"DJ-OB\": \"Obock\",\n \"DJ-TA\": \"Tadjourah\",\n \"DM-02\": \"Saint Andrew\",\n \"DM-03\": \"Saint David\",\n \"DM-04\": \"Saint George\",\n \"DM-05\": \"Saint John\",\n \"DM-06\": \"Saint Joseph\",\n \"DM-07\": \"Saint Luke\",\n \"DM-08\": \"Saint Mark\",\n \"DM-09\": \"Saint Patrick\",\n \"DM-10\": \"Saint Paul\",\n \"DM-11\": \"Saint Peter\",\n \"DO-33\": \"Cibao Nordeste\",\n \"DO-34\": \"Cibao Noroeste\",\n \"DO-35\": \"Cibao Norte\",\n \"DO-36\": \"Cibao Sur\",\n \"DO-37\": \"El Valle\",\n \"DO-38\": \"Enriquillo\",\n \"DO-39\": \"Higuamo\",\n \"DO-40\": \"Ozama\",\n \"DO-41\": \"Valdesia\",\n \"DO-42\": \"Yuma\",\n \"EC-A\": \"Azuay\",\n \"EC-B\": \"Bolívar\",\n \"EC-F\": \"Cañar\",\n \"EC-C\": \"Carchi\",\n \"EC-H\": \"Chimborazo\",\n \"EC-X\": \"Cotopaxi\",\n \"EC-O\": \"El Oro\",\n \"EC-E\": \"Esmeraldas\",\n \"EC-W\": \"Galápagos\",\n \"EC-G\": \"Guayas\",\n \"EC-I\": \"Imbabura\",\n \"EC-L\": \"Loja\",\n \"EC-R\": \"Los Ríos\",\n \"EC-M\": \"Manabí\",\n \"EC-S\": \"Morona Santiago\",\n \"EC-N\": \"Napo\",\n \"EC-D\": \"Orellana\",\n \"EC-Y\": \"Pastaza\",\n \"EC-P\": \"Pichincha\",\n \"EC-SE\": \"Santa Elena\",\n \"EC-SD\": \"Santo Domingo de los Tsáchilas\",\n \"EC-U\": \"Sucumbíos\",\n \"EC-T\": \"Tungurahua\",\n \"EC-Z\": \"Zamora Chinchipe\",\n \"EG-DK\": \"Ad Daqahlīyah\",\n \"EG-BA\": \"Al Baḩr al Aḩmar\",\n \"EG-BH\": \"Al Buḩayrah\",\n \"EG-FYM\": \"Al Fayyūm\",\n \"EG-GH\": \"Al Gharbīyah\",\n \"EG-ALX\": \"Al Iskandarīyah\",\n \"EG-IS\": \"Al Ismā'īlīyah\",\n \"EG-GZ\": \"Al Jīzah\",\n \"EG-MNF\": \"Al Minūfīyah\",\n \"EG-MN\": \"Al Minyā\",\n \"EG-C\": \"Al Qāhirah\",\n \"EG-KB\": \"Al Qalyūbīyah\",\n \"EG-LX\": \"Al Uqşur\",\n \"EG-WAD\": \"Al Wādī al Jadīd\",\n \"EG-SUZ\": \"As Suways\",\n \"EG-SHR\": \"Ash Sharqīyah\",\n \"EG-ASN\": \"Aswān\",\n \"EG-AST\": \"Asyūţ\",\n \"EG-BNS\": \"Banī Suwayf\",\n \"EG-PTS\": \"Būr Sa‘īd\",\n \"EG-DT\": \"Dumyāţ\",\n \"EG-JS\": \"Janūb Sīnā'\",\n \"EG-KFS\": \"Kafr ash Shaykh\",\n \"EG-MT\": \"Maţrūḩ\",\n \"EG-KN\": \"Qinā\",\n \"EG-SIN\": \"Shamāl Sīnā'\",\n \"EG-SHG\": \"Sūhāj\",\n \"SV-AH\": \"Ahuachapán\",\n \"SV-CA\": \"Cabañas\",\n \"SV-CH\": \"Chalatenango\",\n \"SV-CU\": \"Cuscatlán\",\n \"SV-LI\": \"La Libertad\",\n \"SV-PA\": \"La Paz\",\n \"SV-UN\": \"La Unión\",\n \"SV-MO\": \"Morazán\",\n \"SV-SM\": \"San Miguel\",\n \"SV-SS\": \"San Salvador\",\n \"SV-SV\": \"San Vicente\",\n \"SV-SA\": \"Santa Ana\",\n \"SV-SO\": \"Sonsonate\",\n \"SV-US\": \"Usulután\",\n \"GQ-C\": \"Región Continental\",\n \"GQ-I\": \"Región Insular\",\n \"ER-MA\": \"Al Awsaţ\",\n \"ER-DU\": \"Al Janūbī\",\n \"ER-AN\": \"Ansabā\",\n \"ER-DK\": \"Janūbī al Baḩrī al Aḩmar\",\n \"ER-GB\": \"Qāsh-Barkah\",\n \"ER-SK\": \"Shimālī al Baḩrī al Aḩmar\",\n \"EE-37\": \"Harjumaa\",\n \"EE-39\": \"Hiiumaa\",\n \"EE-45\": \"Ida-Virumaa\",\n \"EE-50\": \"Jõgevamaa\",\n \"EE-52\": \"Järvamaa\",\n \"EE-60\": \"Lääne-Virumaa\",\n \"EE-56\": \"Läänemaa\",\n \"EE-64\": \"Põlvamaa\",\n \"EE-68\": \"Pärnumaa\",\n \"EE-71\": \"Raplamaa\",\n \"EE-74\": \"Saaremaa\",\n \"EE-79\": \"Tartumaa\",\n \"EE-81\": \"Valgamaa\",\n \"EE-84\": \"Viljandimaa\",\n \"EE-87\": \"Võrumaa\",\n \"ET-AA\": \"Ādīs Ābeba\",\n \"ET-AF\": \"Āfar\",\n \"ET-AM\": \"Āmara\",\n \"ET-BE\": \"Bīnshangul Gumuz\",\n \"ET-DD\": \"Dirē Dawa\",\n \"ET-GA\": \"Gambēla Hizboch\",\n \"ET-HA\": \"Hārerī Hizb\",\n \"ET-OR\": \"Oromīya\",\n \"ET-SI\": \"Sīdama\",\n \"ET-SO\": \"Sumalē\",\n \"ET-TI\": \"Tigray\",\n \"ET-SN\": \"YeDebub Bihēroch Bihēreseboch na Hizboch\",\n \"ET-SW\": \"YeDebub M‘irab Ītyop’iya Hizboch\",\n \"FJ-C\": \"Central\",\n \"FJ-E\": \"Eastern\",\n \"FJ-N\": \"Northern\",\n \"FJ-W\": \"Western\",\n \"FJ-R\": \"Rotuma\",\n \"FI-01\": \"Ahvenanmaan maakunta\",\n \"FI-02\": \"Etelä-Karjala\",\n \"FI-03\": \"Etelä-Pohjanmaa\",\n \"FI-04\": \"Etelä-Savo\",\n \"FI-05\": \"Kainuu\",\n \"FI-06\": \"Kanta-Häme\",\n \"FI-07\": \"Keski-Pohjanmaa\",\n \"FI-08\": \"Keski-Suomi\",\n \"FI-09\": \"Kymenlaakso\",\n \"FI-10\": \"Lappi\",\n \"FI-11\": \"Pirkanmaa\",\n \"FI-12\": \"Pohjanmaa\",\n \"FI-13\": \"Pohjois-Karjala\",\n \"FI-14\": \"Pohjois-Pohjanmaa\",\n \"FI-15\": \"Pohjois-Savo\",\n \"FI-16\": \"Päijät-Häme\",\n \"FI-17\": \"Satakunta\",\n \"FI-18\": \"Uusimaa\",\n \"FI-19\": \"Varsinais-Suomi\",\n \"FR-ARA\": \"Auvergne-Rhône-Alpes\",\n \"FR-BFC\": \"Bourgogne-Franche-Comté\",\n \"FR-BRE\": \"Bretagne\",\n \"FR-CVL\": \"Centre-Val de Loire\",\n \"FR-20R\": \"Corse\",\n \"FR-GES\": \"Grand Est\",\n \"FR-HDF\": \"Hauts-de-France\",\n \"FR-IDF\": \"Île-de-France\",\n \"FR-NOR\": \"Normandie\",\n \"FR-NAQ\": \"Nouvelle-Aquitaine\",\n \"FR-OCC\": \"Occitanie\",\n \"FR-PDL\": \"Pays-de-la-Loire\",\n \"FR-PAC\": \"Provence-Alpes-Côte-d’Azur\",\n \"GA-1\": \"Estuaire\",\n \"GA-2\": \"Haut-Ogooué\",\n \"GA-3\": \"Moyen-Ogooué\",\n \"GA-4\": \"Ngounié\",\n \"GA-5\": \"Nyanga\",\n \"GA-6\": \"Ogooué-Ivindo\",\n \"GA-7\": \"Ogooué-Lolo\",\n \"GA-8\": \"Ogooué-Maritime\",\n \"GA-9\": \"Woleu-Ntem\",\n \"GM-B\": \"Banjul\",\n \"GM-M\": \"Central River\",\n \"GM-L\": \"Lower River\",\n \"GM-N\": \"North Bank\",\n \"GM-U\": \"Upper River\",\n \"GM-W\": \"Western\",\n \"GE-AB\": \"Abkhazia\",\n \"GE-AJ\": \"Ajaria\",\n \"GE-GU\": \"Guria\",\n \"GE-IM\": \"Imereti\",\n \"GE-KA\": \"K'akheti\",\n \"GE-KK\": \"Kvemo Kartli\",\n \"GE-MM\": \"Mtskheta-Mtianeti\",\n \"GE-RL\": \"Rach'a-Lechkhumi-Kvemo Svaneti\",\n \"GE-SZ\": \"Samegrelo-Zemo Svaneti\",\n \"GE-SJ\": \"Samtskhe-Javakheti\",\n \"GE-SK\": \"Shida Kartli\",\n \"GE-TB\": \"Tbilisi\",\n \"DE-BW\": \"Baden-Württemberg\",\n \"DE-BY\": \"Bayern\",\n \"DE-BE\": \"Berlin\",\n \"DE-BB\": \"Brandenburg\",\n \"DE-HB\": \"Bremen\",\n \"DE-HH\": \"Hamburg\",\n \"DE-HE\": \"Hessen\",\n \"DE-MV\": \"Mecklenburg-Vorpommern\",\n \"DE-NI\": \"Niedersachsen\",\n \"DE-NW\": \"Nordrhein-Westfalen\",\n \"DE-RP\": \"Rheinland-Pfalz\",\n \"DE-SL\": \"Saarland\",\n \"DE-SN\": \"Sachsen\",\n \"DE-ST\": \"Sachsen-Anhalt\",\n \"DE-SH\": \"Schleswig-Holstein\",\n \"DE-TH\": \"Thüringen\",\n \"GH-AF\": \"Ahafo\",\n \"GH-AH\": \"Ashanti\",\n \"GH-BO\": \"Bono\",\n \"GH-BE\": \"Bono East\",\n \"GH-CP\": \"Central\",\n \"GH-EP\": \"Eastern\",\n \"GH-AA\": \"Greater Accra\",\n \"GH-NE\": \"North East\",\n \"GH-NP\": \"Northern\",\n \"GH-OT\": \"Oti\",\n \"GH-SV\": \"Savannah\",\n \"GH-UE\": \"Upper East\",\n \"GH-UW\": \"Upper West\",\n \"GH-TV\": \"Volta\",\n \"GH-WP\": \"Western\",\n \"GH-WN\": \"Western North\",\n \"GR-69\": \"Ágion Óros\",\n \"GR-A\": \"Anatolikí Makedonía kaiThráki\",\n \"GR-I\": \"Attikí\",\n \"GR-G\": \"Dytikí Elláda\",\n \"GR-C\": \"Dytikí Makedonía\",\n \"GR-F\": \"Ionía Nísia\",\n \"GR-D\": \"Ípeiros\",\n \"GR-B\": \"Kentrikí Makedonía\",\n \"GR-M\": \"Kríti\",\n \"GR-L\": \"Nótio Aigaío\",\n \"GR-J\": \"Pelopónnisos\",\n \"GR-H\": \"Stereá Elláda\",\n \"GR-E\": \"Thessalía\",\n \"GR-K\": \"Vóreio Aigaío\",\n \"GL-AV\": \"Avannaata Kommunia\",\n \"GL-KU\": \"Kommune Kujalleq\",\n \"GL-QT\": \"Kommune Qeqertalik\",\n \"GL-SM\": \"Kommuneqarfik Sermersooq\",\n \"GL-QE\": \"Qeqqata Kommunia\",\n \"GD-01\": \"Saint Andrew\",\n \"GD-02\": \"Saint David\",\n \"GD-03\": \"Saint George\",\n \"GD-04\": \"Saint John\",\n \"GD-05\": \"Saint Mark\",\n \"GD-06\": \"Saint Patrick\",\n \"GD-10\": \"Southern Grenadine Islands\",\n \"GT-16\": \"Alta Verapaz\",\n \"GT-15\": \"Baja Verapaz\",\n \"GT-04\": \"Chimaltenango\",\n \"GT-20\": \"Chiquimula\",\n \"GT-02\": \"El Progreso\",\n \"GT-05\": \"Escuintla\",\n \"GT-01\": \"Guatemala\",\n \"GT-13\": \"Huehuetenango\",\n \"GT-18\": \"Izabal\",\n \"GT-21\": \"Jalapa\",\n \"GT-22\": \"Jutiapa\",\n \"GT-17\": \"Petén\",\n \"GT-09\": \"Quetzaltenango\",\n \"GT-14\": \"Quiché\",\n \"GT-11\": \"Retalhuleu\",\n \"GT-03\": \"Sacatepéquez\",\n \"GT-12\": \"San Marcos\",\n \"GT-06\": \"Santa Rosa\",\n \"GT-07\": \"Sololá\",\n \"GT-10\": \"Suchitepéquez\",\n \"GT-08\": \"Totonicapán\",\n \"GT-19\": \"Zacapa\",\n \"GN-B\": \"Boké\",\n \"GN-F\": \"Faranah\",\n \"GN-K\": \"Kankan\",\n \"GN-D\": \"Kindia\",\n \"GN-L\": \"Labé\",\n \"GN-M\": \"Mamou\",\n \"GN-N\": \"Nzérékoré\",\n \"GN-C\": \"Conakry\",\n \"GW-L\": \"Leste\",\n \"GW-N\": \"Norte\",\n \"GW-S\": \"Sul\",\n \"GY-BA\": \"Barima-Waini\",\n \"GY-CU\": \"Cuyuni-Mazaruni\",\n \"GY-DE\": \"Demerara-Mahaica\",\n \"GY-EB\": \"East Berbice-Corentyne\",\n \"GY-ES\": \"Essequibo Islands-West Demerara\",\n \"GY-MA\": \"Mahaica-Berbice\",\n \"GY-PM\": \"Pomeroon-Supenaam\",\n \"GY-PT\": \"Potaro-Siparuni\",\n \"GY-UD\": \"Upper Demerara-Berbice\",\n \"GY-UT\": \"Upper Takutu-Upper Essequibo\",\n \"HT-AR\": \"Artibonite\",\n \"HT-CE\": \"Centre\",\n \"HT-GA\": \"Grande’Anse\",\n \"HT-NI\": \"Nippes\",\n \"HT-ND\": \"Nord\",\n \"HT-NE\": \"Nord-Est\",\n \"HT-NO\": \"Nord-Ouest\",\n \"HT-OU\": \"Ouest\",\n \"HT-SD\": \"Sud\",\n \"HT-SE\": \"Sud-Est\",\n \"HN-AT\": \"Atlántida\",\n \"HN-CH\": \"Choluteca\",\n \"HN-CL\": \"Colón\",\n \"HN-CM\": \"Comayagua\",\n \"HN-CP\": \"Copán\",\n \"HN-CR\": \"Cortés\",\n \"HN-EP\": \"El Paraíso\",\n \"HN-FM\": \"Francisco Morazán\",\n \"HN-GD\": \"Gracias a Dios\",\n \"HN-IN\": \"Intibucá\",\n \"HN-IB\": \"Islas de la Bahía\",\n \"HN-LP\": \"La Paz\",\n \"HN-LE\": \"Lempira\",\n \"HN-OC\": \"Ocotepeque\",\n \"HN-OL\": \"Olancho\",\n \"HN-SB\": \"Santa Bárbara\",\n \"HN-VA\": \"Valle\",\n \"HN-YO\": \"Yoro\",\n \"HU-BK\": \"Bács-Kiskun\",\n \"HU-BA\": \"Baranya\",\n \"HU-BE\": \"Békés\",\n \"HU-BC\": \"Békéscsaba\",\n \"HU-BZ\": \"Borsod-Abaúj-Zemplén\",\n \"HU-BU\": \"Budapest\",\n \"HU-CS\": \"Csongrád-Csanád\",\n \"HU-DE\": \"Debrecen\",\n \"HU-DU\": \"Dunaújváros\",\n \"HU-EG\": \"Eger\",\n \"HU-ER\": \"Érd\",\n \"HU-FE\": \"Fejér\",\n \"HU-GY\": \"Győr\",\n \"HU-GS\": \"Győr-Moson-Sopron\",\n \"HU-HB\": \"Hajdú-Bihar\",\n \"HU-HE\": \"Heves\",\n \"HU-HV\": \"Hódmezővásárhely\",\n \"HU-JN\": \"Jász-Nagykun-Szolnok\",\n \"HU-KV\": \"Kaposvár\",\n \"HU-KM\": \"Kecskemét\",\n \"HU-KE\": \"Komárom-Esztergom\",\n \"HU-MI\": \"Miskolc\",\n \"HU-NK\": \"Nagykanizsa\",\n \"HU-NO\": \"Nógrád\",\n \"HU-NY\": \"Nyíregyháza\",\n \"HU-PS\": \"Pécs\",\n \"HU-PE\": \"Pest\",\n \"HU-ST\": \"Salgótarján\",\n \"HU-SO\": \"Somogy\",\n \"HU-SN\": \"Sopron\",\n \"HU-SZ\": \"Szabolcs-Szatmár-Bereg\",\n \"HU-SD\": \"Szeged\",\n \"HU-SF\": \"Székesfehérvár\",\n \"HU-SS\": \"Szekszárd\",\n \"HU-SK\": \"Szolnok\",\n \"HU-SH\": \"Szombathely\",\n \"HU-TB\": \"Tatabánya\",\n \"HU-TO\": \"Tolna\",\n \"HU-VA\": \"Vas\",\n \"HU-VM\": \"Veszprém\",\n \"HU-VE\": \"Veszprém\",\n \"HU-ZA\": \"Zala\",\n \"HU-ZE\": \"Zalaegerszeg\",\n \"IS-7\": \"Austurland\",\n \"IS-1\": \"Höfuðborgarsvæði\",\n \"IS-6\": \"Norðurland eystra\",\n \"IS-5\": \"Norðurland vestra\",\n \"IS-8\": \"Suðurland\",\n \"IS-2\": \"Suðurnes\",\n \"IS-4\": \"Vestfirðir\",\n \"IS-3\": \"Vesturland\",\n \"IN-AN\": \"Andaman and Nicobar Islands\",\n \"IN-AP\": \"Andhra Pradesh\",\n \"IN-AR\": \"Arunāchal Pradesh\",\n \"IN-AS\": \"Assam\",\n \"IN-BR\": \"Bihār\",\n \"IN-CH\": \"Chandīgarh\",\n \"IN-CG\": \"Chhattīsgarh\",\n \"IN-DH\": \"Dādra and Nagar Haveli and Damān and Diu\",\n \"IN-DL\": \"Delhi\",\n \"IN-GA\": \"Goa\",\n \"IN-GJ\": \"Gujarāt\",\n \"IN-HR\": \"Haryāna\",\n \"IN-HP\": \"Himāchal Pradesh\",\n \"IN-JK\": \"Jammu and Kashmīr\",\n \"IN-JH\": \"Jhārkhand\",\n \"IN-KA\": \"Karnātaka\",\n \"IN-KL\": \"Kerala\",\n \"IN-LA\": \"Ladākh\",\n \"IN-LD\": \"Lakshadweep\",\n \"IN-MP\": \"Madhya Pradesh\",\n \"IN-MH\": \"Mahārāshtra\",\n \"IN-MN\": \"Manipur\",\n \"IN-ML\": \"Meghālaya\",\n \"IN-MZ\": \"Mizoram\",\n \"IN-NL\": \"Nāgāland\",\n \"IN-OD\": \"Odisha\",\n \"IN-PY\": \"Puducherry\",\n \"IN-PB\": \"Punjab\",\n \"IN-RJ\": \"Rājasthān\",\n \"IN-SK\": \"Sikkim\",\n \"IN-TN\": \"Tamil Nādu\",\n \"IN-TS\": \"Telangāna\",\n \"IN-TR\": \"Tripura\",\n \"IN-UP\": \"Uttar Pradesh\",\n \"IN-UK\": \"Uttarākhand\",\n \"IN-WB\": \"West Bengal\",\n \"ID-JW\": \"Jawa\",\n \"ID-KA\": \"Kalimantan\",\n \"ID-ML\": \"Maluku\",\n \"ID-NU\": \"Nusa Tenggara\",\n \"ID-PP\": \"Papua\",\n \"ID-SL\": \"Sulawesi\",\n \"ID-SM\": \"Sumatera\",\n \"IR-30\": \"Alborz\",\n \"IR-24\": \"Ardabīl\",\n \"IR-04\": \"Āz̄ārbāyjān-e Ghārbī\",\n \"IR-03\": \"Āz̄ārbāyjān-e Shārqī\",\n \"IR-18\": \"Būshehr\",\n \"IR-14\": \"Chahār Maḩāl va Bakhtīārī\",\n \"IR-10\": \"Eşfahān\",\n \"IR-07\": \"Fārs\",\n \"IR-01\": \"Gīlān\",\n \"IR-27\": \"Golestān\",\n \"IR-13\": \"Hamadān\",\n \"IR-22\": \"Hormozgān\",\n \"IR-16\": \"Īlām\",\n \"IR-08\": \"Kermān\",\n \"IR-05\": \"Kermānshāh\",\n \"IR-29\": \"Khorāsān-e Jonūbī\",\n \"IR-09\": \"Khorāsān-e Raẕavī\",\n \"IR-28\": \"Khorāsān-e Shomālī\",\n \"IR-06\": \"Khūzestān\",\n \"IR-17\": \"Kohgīlūyeh va Bowyer Aḩmad\",\n \"IR-12\": \"Kordestān\",\n \"IR-15\": \"Lorestān\",\n \"IR-00\": \"Markazī\",\n \"IR-02\": \"Māzandarān\",\n \"IR-26\": \"Qazvīn\",\n \"IR-25\": \"Qom\",\n \"IR-20\": \"Semnān\",\n \"IR-11\": \"Sīstān va Balūchestān\",\n \"IR-23\": \"Tehrān\",\n \"IR-21\": \"Yazd\",\n \"IR-19\": \"Zanjān\",\n \"IQ-AN\": \"Al Anbār\",\n \"IQ-BA\": \"Al Başrah\",\n \"IQ-MU\": \"Al Muthanná\",\n \"IQ-QA\": \"Al Qādisīyah\",\n \"IQ-NA\": \"An Najaf\",\n \"IQ-AR\": \"Arbīl\",\n \"IQ-SU\": \"As Sulaymānīyah\",\n \"IQ-BB\": \"Bābil\",\n \"IQ-BG\": \"Baghdād\",\n \"IQ-DA\": \"Dahūk\",\n \"IQ-DQ\": \"Dhī Qār\",\n \"IQ-DI\": \"Diyālá\",\n \"IQ-KR\": \"Iqlīm Kūrdistān\",\n \"IQ-KA\": \"Karbalā’\",\n \"IQ-KI\": \"Kirkūk\",\n \"IQ-MA\": \"Maysān\",\n \"IQ-NI\": \"Nīnawá\",\n \"IQ-SD\": \"Şalāḩ ad Dīn\",\n \"IQ-WA\": \"Wāsiţ\",\n \"IE-C\": \"Connaught\",\n \"IE-L\": \"Leinster\",\n \"IE-M\": \"Munster\",\n \"IE-U\": \"Ulster\",\n \"IL-D\": \"HaDarom\",\n \"IL-M\": \"HaMerkaz\",\n \"IL-Z\": \"HaTsafon\",\n \"IL-HA\": \"H̱efa\",\n \"IL-TA\": \"Tel Aviv\",\n \"IL-JM\": \"Yerushalayim\",\n \"IT-65\": \"Abruzzo\",\n \"IT-77\": \"Basilicata\",\n \"IT-78\": \"Calabria\",\n \"IT-72\": \"Campania\",\n \"IT-45\": \"Emilia-Romagna\",\n \"IT-36\": \"Friuli Venezia Giulia\",\n \"IT-62\": \"Lazio\",\n \"IT-42\": \"Liguria\",\n \"IT-25\": \"Lombardia\",\n \"IT-57\": \"Marche\",\n \"IT-67\": \"Molise\",\n \"IT-21\": \"Piemonte\",\n \"IT-75\": \"Puglia\",\n \"IT-88\": \"Sardegna\",\n \"IT-82\": \"Sicilia\",\n \"IT-52\": \"Toscana\",\n \"IT-32\": \"Trentino-Alto Adigede\",\n \"IT-55\": \"Umbria\",\n \"IT-23\": \"Valle d'Aostafr\",\n \"IT-34\": \"Veneto\",\n \"JM-13\": \"Clarendon\",\n \"JM-09\": \"Hanover\",\n \"JM-01\": \"Kingston\",\n \"JM-12\": \"Manchester\",\n \"JM-04\": \"Portland\",\n \"JM-02\": \"Saint Andrew\",\n \"JM-06\": \"Saint Ann\",\n \"JM-14\": \"Saint Catherine\",\n \"JM-11\": \"Saint Elizabeth\",\n \"JM-08\": \"Saint James\",\n \"JM-05\": \"Saint Mary\",\n \"JM-03\": \"Saint Thomas\",\n \"JM-07\": \"Trelawny\",\n \"JM-10\": \"Westmoreland\",\n \"JP-23\": \"Aiti\",\n \"JP-05\": \"Akita\",\n \"JP-02\": \"Aomori\",\n \"JP-38\": \"Ehime\",\n \"JP-21\": \"Gihu\",\n \"JP-10\": \"Gunma\",\n \"JP-34\": \"Hirosima\",\n \"JP-01\": \"Hokkaidô\",\n \"JP-18\": \"Hukui\",\n \"JP-40\": \"Hukuoka\",\n \"JP-07\": \"Hukusima\",\n \"JP-28\": \"Hyôgo\",\n \"JP-08\": \"Ibaraki\",\n \"JP-17\": \"Isikawa\",\n \"JP-03\": \"Iwate\",\n \"JP-37\": \"Kagawa\",\n \"JP-46\": \"Kagosima\",\n \"JP-14\": \"Kanagawa\",\n \"JP-39\": \"Kôti\",\n \"JP-43\": \"Kumamoto\",\n \"JP-26\": \"Kyôto\",\n \"JP-24\": \"Mie\",\n \"JP-04\": \"Miyagi\",\n \"JP-45\": \"Miyazaki\",\n \"JP-20\": \"Nagano\",\n \"JP-42\": \"Nagasaki\",\n \"JP-29\": \"Nara\",\n \"JP-15\": \"Niigata\",\n \"JP-44\": \"Ôita\",\n \"JP-33\": \"Okayama\",\n \"JP-47\": \"Okinawa\",\n \"JP-27\": \"Ôsaka\",\n \"JP-41\": \"Saga\",\n \"JP-11\": \"Saitama\",\n \"JP-25\": \"Siga\",\n \"JP-32\": \"Simane\",\n \"JP-22\": \"Sizuoka\",\n \"JP-12\": \"Tiba\",\n \"JP-36\": \"Tokusima\",\n \"JP-13\": \"Tôkyô\",\n \"JP-09\": \"Totigi\",\n \"JP-31\": \"Tottori\",\n \"JP-16\": \"Toyama\",\n \"JP-30\": \"Wakayama\",\n \"JP-06\": \"Yamagata\",\n \"JP-35\": \"Yamaguti\",\n \"JP-19\": \"Yamanasi\",\n \"JO-AJ\": \"‘Ajlūn\",\n \"JO-AQ\": \"Al ‘Aqabah\",\n \"JO-AM\": \"Al ‘A̅şimah\",\n \"JO-BA\": \"Al Balqā’\",\n \"JO-KA\": \"Al Karak\",\n \"JO-MA\": \"Al Mafraq\",\n \"JO-AT\": \"Aţ Ţafīlah\",\n \"JO-AZ\": \"Az Zarqā’\",\n \"JO-IR\": \"Irbid\",\n \"JO-JA\": \"Jarash\",\n \"JO-MN\": \"Ma‘ān\",\n \"JO-MD\": \"Mādabā\",\n \"KZ-10\": \"Abayoblysy\",\n \"KZ-75\": \"Almaty\",\n \"KZ-19\": \"Almatyoblysy\",\n \"KZ-11\": \"Aqmola oblysy\",\n \"KZ-15\": \"Aqtöbe oblysy\",\n \"KZ-71\": \"Astana\",\n \"KZ-23\": \"Atyraūoblysy\",\n \"KZ-27\": \"Batys Qazaqstan oblysy\",\n \"KZ-47\": \"Mangghystaū oblysy\",\n \"KZ-55\": \"Pavlodar oblysy\",\n \"KZ-35\": \"Qaraghandy oblysy\",\n \"KZ-39\": \"Qostanay oblysy\",\n \"KZ-43\": \"Qyzylorda oblysy\",\n \"KZ-63\": \"Shyghys Qazaqstan oblysy\",\n \"KZ-79\": \"Shymkent\",\n \"KZ-59\": \"Soltüstik Qazaqstan oblysy\",\n \"KZ-61\": \"Türkistan oblysy\",\n \"KZ-62\": \"Ulytaūoblysy\",\n \"KZ-31\": \"Zhambyl oblysy\",\n \"KZ-33\": \"Zhetisū oblysy\",\n \"KE-01\": \"Baringo\",\n \"KE-02\": \"Bomet\",\n \"KE-03\": \"Bungoma\",\n \"KE-04\": \"Busia\",\n \"KE-05\": \"Elgeyo/Marakwet\",\n \"KE-06\": \"Embu\",\n \"KE-07\": \"Garissa\",\n \"KE-08\": \"Homa Bay\",\n \"KE-09\": \"Isiolo\",\n \"KE-10\": \"Kajiado\",\n \"KE-11\": \"Kakamega\",\n \"KE-12\": \"Kericho\",\n \"KE-13\": \"Kiambu\",\n \"KE-14\": \"Kilifi\",\n \"KE-15\": \"Kirinyaga\",\n \"KE-16\": \"Kisii\",\n \"KE-17\": \"Kisumu\",\n \"KE-18\": \"Kitui\",\n \"KE-19\": \"Kwale\",\n \"KE-20\": \"Laikipia\",\n \"KE-21\": \"Lamu\",\n \"KE-22\": \"Machakos\",\n \"KE-23\": \"Makueni\",\n \"KE-24\": \"Mandera\",\n \"KE-25\": \"Marsabit\",\n \"KE-26\": \"Meru\",\n \"KE-27\": \"Migori\",\n \"KE-28\": \"Mombasa\",\n \"KE-29\": \"Murang'a\",\n \"KE-30\": \"Nairobi City\",\n \"KE-31\": \"Nakuru\",\n \"KE-32\": \"Nandi\",\n \"KE-33\": \"Narok\",\n \"KE-34\": \"Nyamira\",\n \"KE-35\": \"Nyandarua\",\n \"KE-36\": \"Nyeri\",\n \"KE-37\": \"Samburu\",\n \"KE-38\": \"Siaya\",\n \"KE-39\": \"Taita/Taveta\",\n \"KE-40\": \"Tana River\",\n \"KE-41\": \"Tharaka-Nithi\",\n \"KE-42\": \"Trans Nzoia\",\n \"KE-43\": \"Turkana\",\n \"KE-44\": \"Uasin Gishu\",\n \"KE-45\": \"Vihiga\",\n \"KE-46\": \"Wajir\",\n \"KE-47\": \"West Pokot\",\n \"KI-G\": \"Gilbert Islands\",\n \"KI-L\": \"Line Islands\",\n \"KI-P\": \"Phoenix Islands\",\n \"KP-04\": \"Chagang-do\",\n \"KP-09\": \"Hamgyǒng-bukto\",\n \"KP-08\": \"Hamgyǒng-namdo\",\n \"KP-06\": \"Hwanghae-bukto\",\n \"KP-05\": \"Hwanghae-namdo\",\n \"KP-15\": \"Kaesŏng\",\n \"KP-07\": \"Kangwǒn-do\",\n \"KP-14\": \"Namp’o\",\n \"KP-03\": \"P'yǒngan-bukto\",\n \"KP-02\": \"P'yǒngan-namdo\",\n \"KP-01\": \"P'yǒngyang\",\n \"KP-13\": \"Rasǒn\",\n \"KP-10\": \"Ryanggang-do\",\n \"KR-26\": \"Busan-gwangyeoksi\",\n \"KR-43\": \"Chungcheongbuk-do\",\n \"KR-44\": \"Chungcheongnam-do\",\n \"KR-27\": \"Daegu-gwangyeoksi\",\n \"KR-30\": \"Daejeon-gwangyeoksi\",\n \"KR-42\": \"Gangwon-teukbyeoljachido\",\n \"KR-29\": \"Gwangju-gwangyeoksi\",\n \"KR-41\": \"Gyeonggi-do\",\n \"KR-47\": \"Gyeongsangbuk-do\",\n \"KR-48\": \"Gyeongsangnam-do\",\n \"KR-28\": \"Incheon-gwangyeoksi\",\n \"KR-49\": \"Jeju-teukbyeoljachido\",\n \"KR-45\": \"Jeollabuk-do\",\n \"KR-46\": \"Jeollanam-do\",\n \"KR-50\": \"Sejong\",\n \"KR-11\": \"Seoul-teukbyeolsi\",\n \"KR-31\": \"Ulsan-gwangyeoksi\",\n \"KW-AH\": \"Al Aḩmadī\",\n \"KW-FA\": \"Al Farwānīyah\",\n \"KW-JA\": \"Al Jahrā’\",\n \"KW-KU\": \"Al ‘Āşimah\",\n \"KW-HA\": \"Ḩawallī\",\n \"KW-MU\": \"Mubārak al Kabīr\",\n \"KG-B\": \"Batken\",\n \"KG-GB\": \"Bishkek Shaary\",\n \"KG-C\": \"Chüy\",\n \"KG-J\": \"Jalal-Abad\",\n \"KG-N\": \"Naryn\",\n \"KG-O\": \"Osh\",\n \"KG-GO\": \"Osh Shaary\",\n \"KG-T\": \"Talas\",\n \"KG-Y\": \"Ysyk-Köl\",\n \"LA-AT\": \"Attapu\",\n \"LA-BK\": \"Bokèo\",\n \"LA-BL\": \"Bolikhamxai\",\n \"LA-CH\": \"Champasak\",\n \"LA-HO\": \"Houaphan\",\n \"LA-KH\": \"Khammouan\",\n \"LA-LM\": \"Louang Namtha\",\n \"LA-LP\": \"Louangphabang\",\n \"LA-OU\": \"Oudômxai\",\n \"LA-PH\": \"Phôngsali\",\n \"LA-SL\": \"Salavan\",\n \"LA-SV\": \"Savannakhét\",\n \"LA-VI\": \"Viangchan\",\n \"LA-VT\": \"Viangchan\",\n \"LA-XA\": \"Xaignabouli\",\n \"LA-XS\": \"Xaisômboun\",\n \"LA-XE\": \"Xékong\",\n \"LA-XI\": \"Xiangkhouang\",\n \"LV-002\": \"Aizkraukles novads\",\n \"LV-007\": \"Alūksnes novads\",\n \"LV-111\": \"Augšdaugavas novads\",\n \"LV-011\": \"Ādažu novads\",\n \"LV-015\": \"Balvu novads\",\n \"LV-016\": \"Bauskas novads\",\n \"LV-022\": \"Cēsu novads\",\n \"LV-DGV\": \"Daugavpils\",\n \"LV-112\": \"Dienvidkurzemes Novads\",\n \"LV-026\": \"Dobeles novads\",\n \"LV-033\": \"Gulbenes novads\",\n \"LV-JEL\": \"Jelgava\",\n \"LV-041\": \"Jelgavas novads\",\n \"LV-042\": \"Jēkabpils novads\",\n \"LV-JUR\": \"Jūrmala\",\n \"LV-047\": \"Krāslavas novads\",\n \"LV-050\": \"Kuldīgas novads\",\n \"LV-052\": \"Ķekavas novads\",\n \"LV-LPX\": \"Liepāja\",\n \"LV-054\": \"Limbažu novads\",\n \"LV-056\": \"Līvānu novads\",\n \"LV-058\": \"Ludzas novads\",\n \"LV-059\": \"Madonas novads\",\n \"LV-062\": \"Mārupes novads\",\n \"LV-067\": \"Ogres novads\",\n \"LV-068\": \"Olaines novads\",\n \"LV-073\": \"Preiļu novads\",\n \"LV-REZ\": \"Rēzekne\",\n \"LV-077\": \"Rēzeknes novads\",\n \"LV-RIX\": \"Rīga\",\n \"LV-080\": \"Ropažu novads\",\n \"LV-087\": \"Salaspils novads\",\n \"LV-088\": \"Saldus novads\",\n \"LV-089\": \"Saulkrastu novads\",\n \"LV-091\": \"Siguldas novads\",\n \"LV-094\": \"Smiltenes novads\",\n \"LV-097\": \"Talsu novads\",\n \"LV-099\": \"Tukuma novads\",\n \"LV-101\": \"Valkas novads\",\n \"LV-113\": \"Valmieras Novads\",\n \"LV-102\": \"Varakļānu novads\",\n \"LV-VEN\": \"Ventspils\",\n \"LV-106\": \"Ventspils novads\",\n \"LB-AK\": \"Aakkâr\",\n \"LB-BH\": \"Baalbek-Hermel\",\n \"LB-BI\": \"Béqaa\",\n \"LB-BA\": \"Beyrouth\",\n \"LB-AS\": \"Liban-Nord\",\n \"LB-JA\": \"Liban-Sud\",\n \"LB-JL\": \"Mont-Liban\",\n \"LB-NA\": \"Nabatîyé\",\n \"LS-D\": \"Berea\",\n \"LS-B\": \"Botha-Bothe\",\n \"LS-C\": \"Leribe\",\n \"LS-E\": \"Mafeteng\",\n \"LS-A\": \"Maseru\",\n \"LS-F\": \"Mohale's Hoek\",\n \"LS-J\": \"Mokhotlong\",\n \"LS-H\": \"Qacha's Nek\",\n \"LS-G\": \"Quthing\",\n \"LS-K\": \"Thaba-Tseka\",\n \"LR-BM\": \"Bomi\",\n \"LR-BG\": \"Bong\",\n \"LR-GP\": \"Gbarpolu\",\n \"LR-GB\": \"Grand Bassa\",\n \"LR-CM\": \"Grand Cape Mount\",\n \"LR-GG\": \"Grand Gedeh\",\n \"LR-GK\": \"Grand Kru\",\n \"LR-LO\": \"Lofa\",\n \"LR-MG\": \"Margibi\",\n \"LR-MY\": \"Maryland\",\n \"LR-MO\": \"Montserrado\",\n \"LR-NI\": \"Nimba\",\n \"LR-RI\": \"River Cess\",\n \"LR-RG\": \"River Gee\",\n \"LR-SI\": \"Sinoe\",\n \"LY-BU\": \"Al Buţnān\",\n \"LY-JA\": \"Al Jabal al Akhḑar\",\n \"LY-JG\": \"Al Jabal al Gharbī\",\n \"LY-JI\": \"Al Jafārah\",\n \"LY-JU\": \"Al Jufrah\",\n \"LY-KF\": \"Al Kufrah\",\n \"LY-MJ\": \"Al Marj\",\n \"LY-MB\": \"Al Marqab\",\n \"LY-WA\": \"Al Wāḩāt\",\n \"LY-NQ\": \"An Nuqāţ al Khams\",\n \"LY-ZA\": \"Az Zāwiyah\",\n \"LY-BA\": \"Banghāzī\",\n \"LY-DR\": \"Darnah\",\n \"LY-GT\": \"Ghāt\",\n \"LY-MI\": \"Mişrātah\",\n \"LY-MQ\": \"Murzuq\",\n \"LY-NL\": \"Nālūt\",\n \"LY-SB\": \"Sabhā\",\n \"LY-SR\": \"Surt\",\n \"LY-TB\": \"Ţarābulus\",\n \"LY-WD\": \"Wādī al Ḩayāt\",\n \"LY-WS\": \"Wādī ash Shāţi’\",\n \"LI-01\": \"Balzers\",\n \"LI-02\": \"Eschen\",\n \"LI-03\": \"Gamprin\",\n \"LI-04\": \"Mauren\",\n \"LI-05\": \"Planken\",\n \"LI-06\": \"Ruggell\",\n \"LI-07\": \"Schaan\",\n \"LI-08\": \"Schellenberg\",\n \"LI-09\": \"Triesen\",\n \"LI-10\": \"Triesenberg\",\n \"LI-11\": \"Vaduz\",\n \"LT-AL\": \"Alytaus apskritis\",\n \"LT-KU\": \"Kauno apskritis\",\n \"LT-KL\": \"Klaipėdos apskritis\",\n \"LT-MR\": \"Marijampolės apskritis\",\n \"LT-PN\": \"Panevėžio apskritis\",\n \"LT-SA\": \"Šiaulių apskritis\",\n \"LT-TA\": \"Tauragės apskritis\",\n \"LT-TE\": \"Telšių apskritis\",\n \"LT-UT\": \"Utenos apskritis\",\n \"LT-VL\": \"Vilniaus apskritis\",\n \"LU-CA\": \"Capellen\",\n \"LU-CL\": \"Clervaux\",\n \"LU-DI\": \"Diekirch\",\n \"LU-EC\": \"Echternach\",\n \"LU-ES\": \"Esch-sur-Alzette\",\n \"LU-GR\": \"Grevenmacher\",\n \"LU-LU\": \"Luxembourg\",\n \"LU-ME\": \"Mersch\",\n \"LU-RD\": \"Redange\",\n \"LU-RM\": \"Remich\",\n \"LU-VD\": \"Vianden\",\n \"LU-WI\": \"Wiltz\",\n \"MG-T\": \"Antananarivo\",\n \"MG-D\": \"Antsiranana\",\n \"MG-F\": \"Fianarantsoa\",\n \"MG-M\": \"Mahajanga\",\n \"MG-A\": \"Toamasina\",\n \"MG-U\": \"Toliara\",\n \"MW-N\": \"Chakumpoto\",\n \"MW-S\": \"Chakumwera\",\n \"MW-C\": \"Chapakati\",\n \"MY-01\": \"Johor\",\n \"MY-02\": \"Kedah\",\n \"MY-03\": \"Kelantan\",\n \"MY-04\": \"Melaka\",\n \"MY-05\": \"Negeri Sembilan\",\n \"MY-06\": \"Pahang\",\n \"MY-08\": \"Perak\",\n \"MY-09\": \"Perlis\",\n \"MY-07\": \"Pulau Pinang\",\n \"MY-12\": \"Sabah\",\n \"MY-13\": \"Sarawak\",\n \"MY-10\": \"Selangor\",\n \"MY-11\": \"Terengganu\",\n \"MY-14\": \"Wilayah Persekutuan Kuala Lumpur\",\n \"MY-15\": \"Wilayah Persekutuan Labuan\",\n \"MY-16\": \"Wilayah Persekutuan Putrajaya\",\n \"MV-01\": \"Addu\",\n \"MV-00\": \"Ariatholhu Dhekunuburi\",\n \"MV-02\": \"Ariatholhu Uthuruburi\",\n \"MV-03\": \"Faadhippolhu\",\n \"MV-04\": \"Felidheatholhu\",\n \"MV-29\": \"Fuvammulah\",\n \"MV-05\": \"Hahdhunmathi\",\n \"MV-28\": \"Huvadhuatholhu Dhekunuburi\",\n \"MV-27\": \"Huvadhuatholhu Uthuruburi\",\n \"MV-08\": \"Kolhumadulu\",\n \"MV-MLE\": \"Maale\",\n \"MV-26\": \"Maaleatholhu\",\n \"MV-20\": \"Maalhosmadulu Dhekunuburi\",\n \"MV-13\": \"Maalhosmadulu Uthuruburi\",\n \"MV-25\": \"Miladhunmadulu Dhekunuburi\",\n \"MV-24\": \"Miladhunmadulu Uthuruburi\",\n \"MV-12\": \"Mulakatholhu\",\n \"MV-17\": \"Nilandheatholhu Dhekunuburi\",\n \"MV-14\": \"Nilandheatholhu Uthuruburi\",\n \"MV-23\": \"Thiladhunmathee Dhekunuburi\",\n \"MV-07\": \"Thiladhunmathee Uthuruburi\",\n \"ML-BKO\": \"Bamako\",\n \"ML-7\": \"Gao\",\n \"ML-1\": \"Kayes\",\n \"ML-8\": \"Kidal\",\n \"ML-2\": \"Koulikoro\",\n \"ML-9\": \"Ménaka\",\n \"ML-5\": \"Mopti\",\n \"ML-4\": \"Ségou\",\n \"ML-3\": \"Sikasso\",\n \"ML-10\": \"Taoudénit\",\n \"ML-6\": \"Tombouctou\",\n \"MT-01\": \"Attard\",\n \"MT-02\": \"Balzan\",\n \"MT-03\": \"Birgu\",\n \"MT-04\": \"Birkirkara\",\n \"MT-05\": \"Birżebbuġa\",\n \"MT-06\": \"Bormla\",\n \"MT-07\": \"Dingli\",\n \"MT-08\": \"Fgura\",\n \"MT-09\": \"Floriana\",\n \"MT-10\": \"Fontana\",\n \"MT-11\": \"Gudja\",\n \"MT-12\": \"Gżira\",\n \"MT-13\": \"Għajnsielem\",\n \"MT-14\": \"Għarb\",\n \"MT-15\": \"Għargħur\",\n \"MT-16\": \"Għasri\",\n \"MT-17\": \"Għaxaq\",\n \"MT-18\": \"Ħamrun\",\n \"MT-19\": \"Iklin\",\n \"MT-20\": \"Isla\",\n \"MT-21\": \"Kalkara\",\n \"MT-22\": \"Kerċem\",\n \"MT-23\": \"Kirkop\",\n \"MT-24\": \"Lija\",\n \"MT-25\": \"Luqa\",\n \"MT-26\": \"Marsa\",\n \"MT-27\": \"Marsaskala\",\n \"MT-28\": \"Marsaxlokk\",\n \"MT-29\": \"Mdina\",\n \"MT-30\": \"Mellieħa\",\n \"MT-31\": \"Mġarr\",\n \"MT-32\": \"Mosta\",\n \"MT-33\": \"Mqabba\",\n \"MT-34\": \"Msida\",\n \"MT-35\": \"Mtarfa\",\n \"MT-36\": \"Munxar\",\n \"MT-37\": \"Nadur\",\n \"MT-38\": \"Naxxar\",\n \"MT-39\": \"Paola\",\n \"MT-40\": \"Pembroke\",\n \"MT-41\": \"Pietà\",\n \"MT-42\": \"Qala\",\n \"MT-43\": \"Qormi\",\n \"MT-44\": \"Qrendi\",\n \"MT-45\": \"Rabat Għawdex\",\n \"MT-46\": \"Rabat Malta\",\n \"MT-47\": \"Safi\",\n \"MT-48\": \"San Ġiljan\",\n \"MT-49\": \"San Ġwann\",\n \"MT-50\": \"San Lawrenz\",\n \"MT-51\": \"San Pawl il-Baħar\",\n \"MT-52\": \"Sannat\",\n \"MT-53\": \"Santa Luċija\",\n \"MT-54\": \"Santa Venera\",\n \"MT-55\": \"Siġġiewi\",\n \"MT-56\": \"Sliema\",\n \"MT-57\": \"Swieqi\",\n \"MT-58\": \"Ta' Xbiex\",\n \"MT-59\": \"Tarxien\",\n \"MT-60\": \"Valletta\",\n \"MT-61\": \"Xagħra\",\n \"MT-62\": \"Xewkija\",\n \"MT-63\": \"Xgħajra\",\n \"MT-64\": \"Żabbar\",\n \"MT-65\": \"Żebbuġ Għawdex\",\n \"MT-66\": \"Żebbuġ Malta\",\n \"MT-67\": \"Żejtun\",\n \"MT-68\": \"Żurrieq\",\n \"MH-L\": \"Ralik chain\",\n \"MH-T\": \"Ratak chain\",\n \"MR-07\": \"Adrar\",\n \"MR-03\": \"Assaba\",\n \"MR-05\": \"Brakna\",\n \"MR-08\": \"Dakhlet Nouâdhibou\",\n \"MR-04\": \"Gorgol\",\n \"MR-10\": \"Guidimaka\",\n \"MR-01\": \"Hodh ech Chargui\",\n \"MR-02\": \"Hodh el Gharbi\",\n \"MR-12\": \"Inchiri\",\n \"MR-09\": \"Tagant\",\n \"MR-11\": \"Tiris Zemmour\",\n \"MR-06\": \"Trarza\",\n \"MU-AG\": \"Agalega Islands\",\n \"MU-BL\": \"Black River\",\n \"MU-CC\": \"Cargados Carajos Shoals\",\n \"MU-FL\": \"Flacq\",\n \"MU-GP\": \"Grand Port\",\n \"MU-MO\": \"Moka\",\n \"MU-PA\": \"Pamplemousses\",\n \"MU-PW\": \"Plaines Wilhems\",\n \"MU-PL\": \"Port Louis\",\n \"MU-RR\": \"Rivière du Rempart\",\n \"MU-RO\": \"Rodrigues Island\",\n \"MU-SA\": \"Savanne\",\n \"MX-AGU\": \"Aguascalientes\",\n \"MX-BCN\": \"Baja California\",\n \"MX-BCS\": \"Baja California Sur\",\n \"MX-CAM\": \"Campeche\",\n \"MX-CMX\": \"Ciudad de México\",\n \"MX-COA\": \"Coahuila de Zaragoza\",\n \"MX-COL\": \"Colima\",\n \"MX-CHP\": \"Chiapas\",\n \"MX-CHH\": \"Chihuahua\",\n \"MX-DUR\": \"Durango\",\n \"MX-GUA\": \"Guanajuato\",\n \"MX-GRO\": \"Guerrero\",\n \"MX-HID\": \"Hidalgo\",\n \"MX-JAL\": \"Jalisco\",\n \"MX-MEX\": \"México\",\n \"MX-MIC\": \"Michoacán de Ocampo\",\n \"MX-MOR\": \"Morelos\",\n \"MX-NAY\": \"Nayarit\",\n \"MX-NLE\": \"Nuevo León\",\n \"MX-OAX\": \"Oaxaca\",\n \"MX-PUE\": \"Puebla\",\n \"MX-QUE\": \"Querétaro\",\n \"MX-ROO\": \"Quintana Roo\",\n \"MX-SLP\": \"San Luis Potosí\",\n \"MX-SIN\": \"Sinaloa\",\n \"MX-SON\": \"Sonora\",\n \"MX-TAB\": \"Tabasco\",\n \"MX-TAM\": \"Tamaulipas\",\n \"MX-TLA\": \"Tlaxcala\",\n \"MX-VER\": \"Veracruz de Ignacio de la Llave\",\n \"MX-YUC\": \"Yucatán\",\n \"MX-ZAC\": \"Zacatecas\",\n \"FM-TRK\": \"Chuuk\",\n \"FM-KSA\": \"Kosrae\",\n \"FM-PNI\": \"Pohnpei\",\n \"FM-YAP\": \"Yap\",\n \"MD-AN\": \"Anenii Noi\",\n \"MD-BS\": \"Basarabeasca\",\n \"MD-BA\": \"Bălți\",\n \"MD-BD\": \"Bender\",\n \"MD-BR\": \"Briceni\",\n \"MD-CA\": \"Cahul\",\n \"MD-CT\": \"Cantemir\",\n \"MD-CL\": \"Călărași\",\n \"MD-CS\": \"Căușeni\",\n \"MD-CU\": \"Chișinău\",\n \"MD-CM\": \"Cimișlia\",\n \"MD-CR\": \"Criuleni\",\n \"MD-DO\": \"Dondușeni\",\n \"MD-DR\": \"Drochia\",\n \"MD-DU\": \"Dubăsari\",\n \"MD-ED\": \"Edineț\",\n \"MD-FA\": \"Fălești\",\n \"MD-FL\": \"Florești\",\n \"MD-GA\": \"Găgăuzia\",\n \"MD-GL\": \"Glodeni\",\n \"MD-HI\": \"Hîncești\",\n \"MD-IA\": \"Ialoveni\",\n \"MD-LE\": \"Leova\",\n \"MD-NI\": \"Nisporeni\",\n \"MD-OC\": \"Ocnița\",\n \"MD-OR\": \"Orhei\",\n \"MD-RE\": \"Rezina\",\n \"MD-RI\": \"Rîșcani\",\n \"MD-SI\": \"Sîngerei\",\n \"MD-SO\": \"Soroca\",\n \"MD-SN\": \"Stînga Nistrului\",\n \"MD-ST\": \"Strășeni\",\n \"MD-SD\": \"Șoldănești\",\n \"MD-SV\": \"Ștefan Vodă\",\n \"MD-TA\": \"Taraclia\",\n \"MD-TE\": \"Telenești\",\n \"MD-UN\": \"Ungheni\",\n \"MC-FO\": \"Fontvieille\",\n \"MC-JE\": \"Jardin Exotique\",\n \"MC-CL\": \"La Colle\",\n \"MC-CO\": \"La Condamine\",\n \"MC-GA\": \"La Gare\",\n \"MC-SO\": \"La Source\",\n \"MC-LA\": \"Larvotto\",\n \"MC-MA\": \"Malbousquet\",\n \"MC-MO\": \"Monaco-Ville\",\n \"MC-MG\": \"Moneghetti\",\n \"MC-MC\": \"Monte-Carlo\",\n \"MC-MU\": \"Moulins\",\n \"MC-PH\": \"Port-Hercule\",\n \"MC-SR\": \"Saint-Roman\",\n \"MC-SD\": \"Sainte-Dévote\",\n \"MC-SP\": \"Spélugues\",\n \"MC-VR\": \"Vallon de la Rousse\",\n \"MN-073\": \"Arhangay\",\n \"MN-069\": \"Bayanhongor\",\n \"MN-071\": \"Bayan-Ölgiy\",\n \"MN-067\": \"Bulgan\",\n \"MN-037\": \"Darhan uul\",\n \"MN-061\": \"Dornod\",\n \"MN-063\": \"Dornogovĭ\",\n \"MN-059\": \"Dundgovĭ\",\n \"MN-057\": \"Dzavhan\",\n \"MN-065\": \"Govĭ-Altay\",\n \"MN-064\": \"Govĭ-Sümber\",\n \"MN-039\": \"Hentiy\",\n \"MN-043\": \"Hovd\",\n \"MN-041\": \"Hövsgöl\",\n \"MN-053\": \"Ömnögovĭ\",\n \"MN-035\": \"Orhon\",\n \"MN-055\": \"Övörhangay\",\n \"MN-049\": \"Selenge\",\n \"MN-051\": \"Sühbaatar\",\n \"MN-047\": \"Töv\",\n \"MN-1\": \"Ulaanbaatar\",\n \"MN-046\": \"Uvs\",\n \"MA-05\": \"Béni Mellal-Khénifra\",\n \"MA-06\": \"Casablanca-Settat\",\n \"MA-12\": \"Dakhla-Oued Ed-Dahab\",\n \"MA-08\": \"Drâa-Tafilalet\",\n \"MA-03\": \"Fès-Meknès\",\n \"MA-10\": \"Guelmim-Oued Noun\",\n \"MA-02\": \"L'Oriental\",\n \"MA-11\": \"Laâyoune-Sakia El Hamra\",\n \"MA-07\": \"Marrakech-Safi\",\n \"MA-04\": \"Rabat-Salé-Kénitra\",\n \"MA-09\": \"Souss-Massa\",\n \"MA-01\": \"Tanger-Tétouan-Al Hoceïma\",\n \"MZ-P\": \"Cabo Delgado\",\n \"MZ-G\": \"Gaza\",\n \"MZ-I\": \"Inhambane\",\n \"MZ-B\": \"Manica\",\n \"MZ-MPM\": \"Maputo\",\n \"MZ-L\": \"Maputo\",\n \"MZ-N\": \"Nampula\",\n \"MZ-A\": \"Niassa\",\n \"MZ-S\": \"Sofala\",\n \"MZ-T\": \"Tete\",\n \"MZ-Q\": \"Zambézia\",\n \"MM-07\": \"Ayeyarwady\",\n \"MM-02\": \"Bago\",\n \"MM-14\": \"Chin\",\n \"MM-11\": \"Kachin\",\n \"MM-12\": \"Kayah\",\n \"MM-13\": \"Kayin\",\n \"MM-03\": \"Magway\",\n \"MM-04\": \"Mandalay\",\n \"MM-15\": \"Mon\",\n \"MM-18\": \"Nay Pyi Taw\",\n \"MM-16\": \"Rakhine\",\n \"MM-01\": \"Sagaing\",\n \"MM-17\": \"Shan\",\n \"MM-05\": \"Tanintharyi\",\n \"MM-06\": \"Yangon\",\n \"NA-ER\": \"Erongo\",\n \"NA-HA\": \"Hardap\",\n \"NA-KA\": \"//Karas\",\n \"NA-KE\": \"Kavango East\",\n \"NA-KW\": \"Kavango West\",\n \"NA-KH\": \"Khomas\",\n \"NA-KU\": \"Kunene\",\n \"NA-OW\": \"Ohangwena\",\n \"NA-OH\": \"Omaheke\",\n \"NA-OS\": \"Omusati\",\n \"NA-ON\": \"Oshana\",\n \"NA-OT\": \"Oshikoto\",\n \"NA-OD\": \"Otjozondjupa\",\n \"NA-CA\": \"Zambezi\",\n \"NR-01\": \"Aiwo\",\n \"NR-02\": \"Anabar\",\n \"NR-03\": \"Anetan\",\n \"NR-04\": \"Anibare\",\n \"NR-05\": \"Baitsi\",\n \"NR-06\": \"Boe\",\n \"NR-07\": \"Buada\",\n \"NR-08\": \"Denigomodu\",\n \"NR-09\": \"Ewa\",\n \"NR-10\": \"Ijuw\",\n \"NR-11\": \"Meneng\",\n \"NR-12\": \"Nibok\",\n \"NR-13\": \"Uaboe\",\n \"NR-14\": \"Yaren\",\n \"NP-P3\": \"Bāgmatī\",\n \"NP-P4\": \"Gaṇḍakī\",\n \"NP-P6\": \"Karṇālī\",\n \"NP-P1\": \"Koshī\",\n \"NP-P5\": \"Lumbinī\",\n \"NP-P2\": \"Madhesh\",\n \"NP-P7\": \"Sudūrpashchim\",\n \"NL-DR\": \"Drenthe\",\n \"NL-FL\": \"Flevoland\",\n \"NL-FR\": \"Fryslânfy\",\n \"NL-GE\": \"Gelderland\",\n \"NL-GR\": \"Groningen\",\n \"NL-LI\": \"Limburg\",\n \"NL-NB\": \"Noord-Brabant\",\n \"NL-NH\": \"Noord-Holland\",\n \"NL-OV\": \"Overijssel\",\n \"NL-UT\": \"Utrecht\",\n \"NL-ZE\": \"Zeeland\",\n \"NL-ZH\": \"Zuid-Holland\",\n \"NZ-AUK\": \"Auckland\",\n \"NZ-BOP\": \"Bay of Plenty\",\n \"NZ-CAN\": \"Canterbury\",\n \"NZ-CIT\": \"Chatham Islands Territory\",\n \"NZ-GIS\": \"Gisborne\",\n \"NZ-WGN\": \"Greater Wellington\",\n \"NZ-HKB\": \"Hawke's Bay\",\n \"NZ-MWT\": \"Manawatū-Whanganui\",\n \"NZ-MBH\": \"Marlborough\",\n \"NZ-NSN\": \"Nelson\",\n \"NZ-NTL\": \"Northland\",\n \"NZ-OTA\": \"Otago\",\n \"NZ-STL\": \"Southland\",\n \"NZ-TKI\": \"Taranaki\",\n \"NZ-TAS\": \"Tasman\",\n \"NZ-WKO\": \"Waikato\",\n \"NZ-WTC\": \"West Coast\",\n \"NI-BO\": \"Boaco\",\n \"NI-CA\": \"Carazo\",\n \"NI-CI\": \"Chinandega\",\n \"NI-CO\": \"Chontales\",\n \"NI-AN\": \"Costa Caribe Norte\",\n \"NI-AS\": \"Costa Caribe Sur\",\n \"NI-ES\": \"Estelí\",\n \"NI-GR\": \"Granada\",\n \"NI-JI\": \"Jinotega\",\n \"NI-LE\": \"León\",\n \"NI-MD\": \"Madriz\",\n \"NI-MN\": \"Managua\",\n \"NI-MS\": \"Masaya\",\n \"NI-MT\": \"Matagalpa\",\n \"NI-NS\": \"Nueva Segovia\",\n \"NI-SJ\": \"Río San Juan\",\n \"NI-RI\": \"Rivas\",\n \"NE-1\": \"Agadez\",\n \"NE-2\": \"Diffa\",\n \"NE-3\": \"Dosso\",\n \"NE-4\": \"Maradi\",\n \"NE-8\": \"Niamey\",\n \"NE-5\": \"Tahoua\",\n \"NE-6\": \"Tillabéri\",\n \"NE-7\": \"Zinder\",\n \"NG-AB\": \"Abia\",\n \"NG-FC\": \"Abuja Federal Capital Territory\",\n \"NG-AD\": \"Adamawa\",\n \"NG-AK\": \"Akwa Ibom\",\n \"NG-AN\": \"Anambra\",\n \"NG-BA\": \"Bauchi\",\n \"NG-BY\": \"Bayelsa\",\n \"NG-BE\": \"Benue\",\n \"NG-BO\": \"Borno\",\n \"NG-CR\": \"Cross River\",\n \"NG-DE\": \"Delta\",\n \"NG-EB\": \"Ebonyi\",\n \"NG-ED\": \"Edo\",\n \"NG-EK\": \"Ekiti\",\n \"NG-EN\": \"Enugu\",\n \"NG-GO\": \"Gombe\",\n \"NG-IM\": \"Imo\",\n \"NG-JI\": \"Jigawa\",\n \"NG-KD\": \"Kaduna\",\n \"NG-KN\": \"Kano\",\n \"NG-KT\": \"Katsina\",\n \"NG-KE\": \"Kebbi\",\n \"NG-KO\": \"Kogi\",\n \"NG-KW\": \"Kwara\",\n \"NG-LA\": \"Lagos\",\n \"NG-NA\": \"Nasarawa\",\n \"NG-NI\": \"Niger\",\n \"NG-OG\": \"Ogun\",\n \"NG-ON\": \"Ondo\",\n \"NG-OS\": \"Osun\",\n \"NG-OY\": \"Oyo\",\n \"NG-PL\": \"Plateau\",\n \"NG-RI\": \"Rivers\",\n \"NG-SO\": \"Sokoto\",\n \"NG-TA\": \"Taraba\",\n \"NG-YO\": \"Yobe\",\n \"NG-ZA\": \"Zamfara\",\n \"MK-801\": \"Aerodrom\",\n \"MK-802\": \"Aračinovo\",\n \"MK-201\": \"Berovo\",\n \"MK-501\": \"Bitola\",\n \"MK-401\": \"Bogdanci\",\n \"MK-601\": \"Bogovinje\",\n \"MK-402\": \"Bosilovo\",\n \"MK-602\": \"Brvenica\",\n \"MK-803\": \"Butel\",\n \"MK-814\": \"Centar\",\n \"MK-313\": \"Centar Župa\",\n \"MK-815\": \"Čair\",\n \"MK-109\": \"Čaška\",\n \"MK-210\": \"Češinovo-Obleševo\",\n \"MK-816\": \"Čučer-Sandevo\",\n \"MK-303\": \"Debar\",\n \"MK-304\": \"Debrca\",\n \"MK-203\": \"Delčevo\",\n \"MK-502\": \"Demir Hisar\",\n \"MK-103\": \"Demir Kapija\",\n \"MK-406\": \"Dojran\",\n \"MK-503\": \"Dolneni\",\n \"MK-804\": \"Gazi Baba\",\n \"MK-405\": \"Gevgelija\",\n \"MK-805\": \"Gjorče Petrov\",\n \"MK-604\": \"Gostivar\",\n \"MK-102\": \"Gradsko\",\n \"MK-807\": \"Ilinden\",\n \"MK-606\": \"Jegunovce\",\n \"MK-205\": \"Karbinci\",\n \"MK-808\": \"Karpoš\",\n \"MK-104\": \"Kavadarci\",\n \"MK-307\": \"Kičevo\",\n \"MK-809\": \"Kisela Voda\",\n \"MK-206\": \"Kočani\",\n \"MK-407\": \"Konče\",\n \"MK-701\": \"Kratovo\",\n \"MK-702\": \"Kriva Palanka\",\n \"MK-504\": \"Krivogaštani\",\n \"MK-505\": \"Kruševo\",\n \"MK-703\": \"Kumanovo\",\n \"MK-704\": \"Lipkovo\",\n \"MK-105\": \"Lozovo\",\n \"MK-207\": \"Makedonska Kamenica\",\n \"MK-308\": \"Makedonski Brod\",\n \"MK-607\": \"Mavrovo i Rostuše\",\n \"MK-506\": \"Mogila\",\n \"MK-106\": \"Negotino\",\n \"MK-507\": \"Novaci\",\n \"MK-408\": \"Novo Selo\",\n \"MK-310\": \"Ohrid\",\n \"MK-208\": \"Pehčevo\",\n \"MK-810\": \"Petrovec\",\n \"MK-311\": \"Plasnica\",\n \"MK-508\": \"Prilep\",\n \"MK-209\": \"Probištip\",\n \"MK-409\": \"Radoviš\",\n \"MK-705\": \"Rankovce\",\n \"MK-509\": \"Resen\",\n \"MK-107\": \"Rosoman\",\n \"MK-811\": \"Saraj\",\n \"MK-812\": \"Sopište\",\n \"MK-706\": \"Staro Nagoričane\",\n \"MK-312\": \"Struga\",\n \"MK-410\": \"Strumica\",\n \"MK-813\": \"Studeničani\",\n \"MK-108\": \"Sveti Nikole\",\n \"MK-211\": \"Štip\",\n \"MK-817\": \"Šuto Orizari\",\n \"MK-608\": \"Tearce\",\n \"MK-609\": \"Tetovo\",\n \"MK-403\": \"Valandovo\",\n \"MK-404\": \"Vasilevo\",\n \"MK-101\": \"Veles\",\n \"MK-301\": \"Vevčani\",\n \"MK-202\": \"Vinica\",\n \"MK-603\": \"Vrapčište\",\n \"MK-806\": \"Zelenikovo\",\n \"MK-204\": \"Zrnovci\",\n \"MK-605\": \"Želino\",\n \"NO-42\": \"Agder\",\n \"NO-34\": \"Innlandet\",\n \"NO-22\": \"Jan Mayen\",\n \"NO-15\": \"Møre og Romsdal\",\n \"NO-18\": \"Nordland\",\n \"NO-03\": \"Oslo\",\n \"NO-11\": \"Rogaland\",\n \"NO-21\": \"Svalbard\",\n \"NO-54\": \"Troms og Finnmarksefkv\",\n \"NO-50\": \"Trøndelagsma\",\n \"NO-38\": \"Vestfold og Telemark\",\n \"NO-46\": \"Vestland\",\n \"NO-30\": \"Viken\",\n \"OM-DA\": \"Ad Dākhilīyah\",\n \"OM-BU\": \"Al Buraymī\",\n \"OM-WU\": \"Al Wusţá\",\n \"OM-ZA\": \"Az̧ Z̧āhirah\",\n \"OM-BJ\": \"Janūb al Bāţinah\",\n \"OM-SJ\": \"Janūb ash Sharqīyah\",\n \"OM-MA\": \"Masqaţ\",\n \"OM-MU\": \"Musandam\",\n \"OM-BS\": \"Shamāl al Bāţinah\",\n \"OM-SS\": \"Shamāl ash Sharqīyah\",\n \"OM-ZU\": \"Z̧ufār\",\n \"PK-JK\": \"Āzād Jammūñ o Kashmīr\",\n \"PK-BA\": \"Balōchistān\",\n \"PK-GB\": \"Gilgit-Baltistān\",\n \"PK-IS\": \"Islāmābād\",\n \"PK-KP\": \"Khaībar Pakhtūnkhwā\",\n \"PK-PB\": \"Panjāb\",\n \"PK-SD\": \"Sindh\",\n \"PW-002\": \"Aimeliik\",\n \"PW-004\": \"Airai\",\n \"PW-010\": \"Angaur\",\n \"PW-050\": \"Hatohobei\",\n \"PW-100\": \"Kayangel\",\n \"PW-150\": \"Koror\",\n \"PW-212\": \"Melekeok\",\n \"PW-214\": \"Ngaraard\",\n \"PW-218\": \"Ngarchelong\",\n \"PW-222\": \"Ngardmau\",\n \"PW-224\": \"Ngatpang\",\n \"PW-226\": \"Ngchesar\",\n \"PW-227\": \"Ngeremlengui\",\n \"PW-228\": \"Ngiwal\",\n \"PW-350\": \"Peleliu\",\n \"PW-370\": \"Sonsorol\",\n \"PS-BTH\": \"Bayt Laḩm\",\n \"PS-DEB\": \"Dayr al Balaḩ\",\n \"PS-GZA\": \"Ghazzah\",\n \"PS-HBN\": \"Al Khalīl\",\n \"PS-JEN\": \"Janīn\",\n \"PS-JRH\": \"Arīḩā wal Aghwār\",\n \"PS-JEM\": \"Al Quds\",\n \"PS-KYS\": \"Khān Yūnis\",\n \"PS-NBS\": \"Nāblus\",\n \"PS-NGZ\": \"Shamāl Ghazzah\",\n \"PS-QQA\": \"Qalqīlyah\",\n \"PS-RFH\": \"Rafaḩ\",\n \"PS-RBH\": \"Rām Allāh wal Bīrah\",\n \"PS-SLT\": \"Salfīt\",\n \"PS-TBS\": \"Ţūbās\",\n \"PS-TKM\": \"Ţūlkarm\",\n \"PA-1\": \"Bocas del Toro\",\n \"PA-4\": \"Chiriquí\",\n \"PA-2\": \"Coclé\",\n \"PA-3\": \"Colón\",\n \"PA-5\": \"Darién\",\n \"PA-EM\": \"Emberá\",\n \"PA-KY\": \"Guna Yala\",\n \"PA-6\": \"Herrera\",\n \"PA-7\": \"Los Santos\",\n \"PA-NT\": \"Naso Tjër Di\",\n \"PA-NB\": \"Ngäbe-Buglé\",\n \"PA-8\": \"Panamá\",\n \"PA-10\": \"Panamá Oeste\",\n \"PA-9\": \"Veraguas\",\n \"PG-NSB\": \"Bougainville\",\n \"PG-CPM\": \"Central\",\n \"PG-CPK\": \"Chimbu\",\n \"PG-EBR\": \"East New Britain\",\n \"PG-ESW\": \"East Sepik\",\n \"PG-EHG\": \"Eastern Highlands\",\n \"PG-EPW\": \"Enga\",\n \"PG-GPK\": \"Gulf\",\n \"PG-HLA\": \"Hela\",\n \"PG-JWK\": \"Jiwaka\",\n \"PG-MPM\": \"Madang\",\n \"PG-MRL\": \"Manus\",\n \"PG-MBA\": \"Milne Bay\",\n \"PG-MPL\": \"Morobe\",\n \"PG-NCD\": \"National Capital District\",\n \"PG-NIK\": \"New Ireland\",\n \"PG-NPP\": \"Northern\",\n \"PG-SHM\": \"Southern Highlands\",\n \"PG-WBK\": \"West New Britain\",\n \"PG-SAN\": \"West Sepik\",\n \"PG-WPD\": \"Western\",\n \"PG-WHM\": \"Western Highlands\",\n \"PY-16\": \"Alto Paraguay\",\n \"PY-10\": \"Alto Paraná\",\n \"PY-13\": \"Amambay\",\n \"PY-ASU\": \"Asunción\",\n \"PY-19\": \"Boquerón\",\n \"PY-5\": \"Caaguazú\",\n \"PY-6\": \"Caazapá\",\n \"PY-14\": \"Canindeyú\",\n \"PY-11\": \"Central\",\n \"PY-1\": \"Concepción\",\n \"PY-3\": \"Cordillera\",\n \"PY-4\": \"Guairá\",\n \"PY-7\": \"Itapúa\",\n \"PY-8\": \"Misiones\",\n \"PY-12\": \"Ñeembucú\",\n \"PY-9\": \"Paraguarí\",\n \"PY-15\": \"Presidente Hayes\",\n \"PY-2\": \"San Pedro\",\n \"PE-AMA\": \"Amazonas\",\n \"PE-ANC\": \"Ancash\",\n \"PE-APU\": \"Apurímac\",\n \"PE-ARE\": \"Arequipa\",\n \"PE-AYA\": \"Ayacucho\",\n \"PE-CAJ\": \"Cajamarca\",\n \"PE-CUS\": \"Cusco\",\n \"PE-CAL\": \"El Callao\",\n \"PE-HUV\": \"Huancavelica\",\n \"PE-HUC\": \"Huánuco\",\n \"PE-ICA\": \"Ica\",\n \"PE-JUN\": \"Junín\",\n \"PE-LAL\": \"La Libertad\",\n \"PE-LAM\": \"Lambayeque\",\n \"PE-LIM\": \"Lima\",\n \"PE-LOR\": \"Loreto\",\n \"PE-MDD\": \"Madre de Dios\",\n \"PE-MOQ\": \"Moquegua\",\n \"PE-LMA\": \"Municipalidad Metropolitana de Lima\",\n \"PE-PAS\": \"Pasco\",\n \"PE-PIU\": \"Piura\",\n \"PE-PUN\": \"Puno\",\n \"PE-SAM\": \"San Martín\",\n \"PE-TAC\": \"Tacna\",\n \"PE-TUM\": \"Tumbes\",\n \"PE-UCA\": \"Ucayali\",\n \"PH-14\": \"Autonomous Region in Muslim Mindanao\",\n \"PH-05\": \"Bicol\",\n \"PH-02\": \"Cagayan Valley\",\n \"PH-40\": \"Calabarzon\",\n \"PH-13\": \"Caraga\",\n \"PH-03\": \"Central Luzon\",\n \"PH-07\": \"Central Visayas\",\n \"PH-15\": \"Cordillera Administrative Region\",\n \"PH-11\": \"Davao\",\n \"PH-08\": \"Eastern Visayas\",\n \"PH-01\": \"Ilocos\",\n \"PH-41\": \"Mimaropa\",\n \"PH-00\": \"National Capital Region\",\n \"PH-10\": \"Northern Mindanao\",\n \"PH-12\": \"Soccsksargen\",\n \"PH-06\": \"Western Visayas\",\n \"PH-09\": \"Zamboanga Peninsula\",\n \"PL-02\": \"Dolnośląskie\",\n \"PL-04\": \"Kujawsko-Pomorskie\",\n \"PL-06\": \"Lubelskie\",\n \"PL-08\": \"Lubuskie\",\n \"PL-10\": \"Łódzkie\",\n \"PL-12\": \"Małopolskie\",\n \"PL-14\": \"Mazowieckie\",\n \"PL-16\": \"Opolskie\",\n \"PL-18\": \"Podkarpackie\",\n \"PL-20\": \"Podlaskie\",\n \"PL-22\": \"Pomorskie\",\n \"PL-24\": \"Śląskie\",\n \"PL-26\": \"Świętokrzyskie\",\n \"PL-28\": \"Warmińsko-Mazurskie\",\n \"PL-30\": \"Wielkopolskie\",\n \"PL-32\": \"Zachodniopomorskie\",\n \"PT-01\": \"Aveiro\",\n \"PT-02\": \"Beja\",\n \"PT-03\": \"Braga\",\n \"PT-04\": \"Bragança\",\n \"PT-05\": \"Castelo Branco\",\n \"PT-06\": \"Coimbra\",\n \"PT-07\": \"Évora\",\n \"PT-08\": \"Faro\",\n \"PT-09\": \"Guarda\",\n \"PT-10\": \"Leiria\",\n \"PT-11\": \"Lisboa\",\n \"PT-12\": \"Portalegre\",\n \"PT-13\": \"Porto\",\n \"PT-30\": \"Região Autónoma da Madeira\",\n \"PT-20\": \"Região Autónoma dos Açores\",\n \"PT-14\": \"Santarém\",\n \"PT-15\": \"Setúbal\",\n \"PT-16\": \"Viana do Castelo\",\n \"PT-17\": \"Vila Real\",\n \"PT-18\": \"Viseu\",\n \"QA-DA\": \"Ad Dawḩah\",\n \"QA-KH\": \"Al Khawr wa adh Dhakhīrah\",\n \"QA-WA\": \"Al Wakrah\",\n \"QA-RA\": \"Ar Rayyān\",\n \"QA-MS\": \"Ash Shamāl\",\n \"QA-SH\": \"Ash Shīḩānīyah\",\n \"QA-ZA\": \"Az̧ Z̧a‘āyin\",\n \"QA-US\": \"Umm Şalāl\",\n \"RO-AB\": \"Alba\",\n \"RO-AR\": \"Arad\",\n \"RO-AG\": \"Argeș\",\n \"RO-BC\": \"Bacău\",\n \"RO-BH\": \"Bihor\",\n \"RO-BN\": \"Bistrița-Năsăud\",\n \"RO-BT\": \"Botoșani\",\n \"RO-BV\": \"Brașov\",\n \"RO-BR\": \"Brăila\",\n \"RO-B\": \"București\",\n \"RO-BZ\": \"Buzău\",\n \"RO-CS\": \"Caraș-Severin\",\n \"RO-CL\": \"Călărași\",\n \"RO-CJ\": \"Cluj\",\n \"RO-CT\": \"Constanța\",\n \"RO-CV\": \"Covasna\",\n \"RO-DB\": \"Dâmbovița\",\n \"RO-DJ\": \"Dolj\",\n \"RO-GL\": \"Galați\",\n \"RO-GR\": \"Giurgiu\",\n \"RO-GJ\": \"Gorj\",\n \"RO-HR\": \"Harghita\",\n \"RO-HD\": \"Hunedoara\",\n \"RO-IL\": \"Ialomița\",\n \"RO-IS\": \"Iași\",\n \"RO-IF\": \"Ilfov\",\n \"RO-MM\": \"Maramureș\",\n \"RO-MH\": \"Mehedinți\",\n \"RO-MS\": \"Mureș\",\n \"RO-NT\": \"Neamț\",\n \"RO-OT\": \"Olt\",\n \"RO-PH\": \"Prahova\",\n \"RO-SM\": \"Satu Mare\",\n \"RO-SJ\": \"Sălaj\",\n \"RO-SB\": \"Sibiu\",\n \"RO-SV\": \"Suceava\",\n \"RO-TR\": \"Teleorman\",\n \"RO-TM\": \"Timiș\",\n \"RO-TL\": \"Tulcea\",\n \"RO-VS\": \"Vaslui\",\n \"RO-VL\": \"Vâlcea\",\n \"RO-VN\": \"Vrancea\",\n \"RU-AD\": \"Adygeya\",\n \"RU-AL\": \"Altay\",\n \"RU-ALT\": \"Altayskiy kray\",\n \"RU-AMU\": \"Amurskaya oblast'\",\n \"RU-ARK\": \"Arkhangel'skaya oblast'\",\n \"RU-AST\": \"Astrakhanskaya oblast'\",\n \"RU-BA\": \"Bashkortostan\",\n \"RU-BEL\": \"Belgorodskaya oblast'\",\n \"RU-BRY\": \"Bryanskaya oblast'\",\n \"RU-BU\": \"Buryatiya\",\n \"RU-CE\": \"Chechenskaya Respublika\",\n \"RU-CHE\": \"Chelyabinskaya oblast'\",\n \"RU-CHU\": \"Chukotskiy avtonomnyy okrug\",\n \"RU-CU\": \"Chuvashskaya Respublika\",\n \"RU-DA\": \"Dagestan\",\n \"RU-IN\": \"Ingushetiya\",\n \"RU-IRK\": \"Irkutskaya oblast'\",\n \"RU-IVA\": \"Ivanovskaya oblast'\",\n \"RU-KB\": \"Kabardino-BalkarskayaRespublika\",\n \"RU-KGD\": \"Kaliningradskaya oblast'\",\n \"RU-KL\": \"Kalmykiya\",\n \"RU-KLU\": \"Kaluzhskaya oblast'\",\n \"RU-KAM\": \"Kamchatskiy kray\",\n \"RU-KC\": \"Karachayevo-CherkesskayaRespublika\",\n \"RU-KR\": \"Kareliya\",\n \"RU-KEM\": \"Kemerovskaya oblast'\",\n \"RU-KHA\": \"Khabarovskiy kray\",\n \"RU-KK\": \"Khakasiya\",\n \"RU-KHM\": \"Khanty-Mansiyskiyavtonomnyy okrug\",\n \"RU-KIR\": \"Kirovskaya oblast'\",\n \"RU-KO\": \"Komi\",\n \"RU-KOS\": \"Kostromskaya oblast'\",\n \"RU-KDA\": \"Krasnodarskiy kray\",\n \"RU-KYA\": \"Krasnoyarskiy kray\",\n \"RU-KGN\": \"Kurganskaya oblast'\",\n \"RU-KRS\": \"Kurskaya oblast'\",\n \"RU-LEN\": \"Leningradskayaoblast'\",\n \"RU-LIP\": \"Lipetskaya oblast'\",\n \"RU-MAG\": \"Magadanskaya oblast'\",\n \"RU-ME\": \"Mariy El\",\n \"RU-MO\": \"Mordoviya\",\n \"RU-MOS\": \"Moskovskaya oblast'\",\n \"RU-MOW\": \"Moskva\",\n \"RU-MUR\": \"Murmanskaya oblast'\",\n \"RU-NEN\": \"Nenetskiyavtonomnyy okrug\",\n \"RU-NIZ\": \"Nizhegorodskaya oblast'\",\n \"RU-NGR\": \"Novgorodskaya oblast'\",\n \"RU-NVS\": \"Novosibirskayaoblast'\",\n \"RU-OMS\": \"Omskaya oblast'\",\n \"RU-ORE\": \"Orenburgskaya oblast'\",\n \"RU-ORL\": \"Orlovskaya oblast'\",\n \"RU-PNZ\": \"Penzenskaya oblast'\",\n \"RU-PER\": \"Permskiy kray\",\n \"RU-PRI\": \"Primorskiy kray\",\n \"RU-PSK\": \"Pskovskaya oblast'\",\n \"RU-ROS\": \"Rostovskaya oblast'\",\n \"RU-RYA\": \"Ryazanskaya oblast'\",\n \"RU-SA\": \"Saha\",\n \"RU-SAK\": \"Sakhalinskaya oblast'\",\n \"RU-SAM\": \"Samarskaya oblast'\",\n \"RU-SPE\": \"Sankt-Peterburg\",\n \"RU-SAR\": \"Saratovskaya oblast'\",\n \"RU-SE\": \"Severnaya Osetiya\",\n \"RU-SMO\": \"Smolenskaya oblast'\",\n \"RU-STA\": \"Stavropol'skiy kray\",\n \"RU-SVE\": \"Sverdlovskaya oblast'\",\n \"RU-TAM\": \"Tambovskaya oblast'\",\n \"RU-TA\": \"Tatarstan\",\n \"RU-TOM\": \"Tomskaya oblast'\",\n \"RU-TUL\": \"Tul'skaya oblast'\",\n \"RU-TVE\": \"Tverskaya oblast'\",\n \"RU-TYU\": \"Tyumenskaya oblast'\",\n \"RU-TY\": \"Tyva\",\n \"RU-UD\": \"Udmurtskaya Respublika\",\n \"RU-ULY\": \"Ul'yanovskaya oblast'\",\n \"RU-VLA\": \"Vladimirskayaoblast'\",\n \"RU-VGG\": \"Volgogradskayaoblast'\",\n \"RU-VLG\": \"Vologodskaya oblast'\",\n \"RU-VOR\": \"Voronezhskaya oblast'\",\n \"RU-YAN\": \"Yamalo-Nenetskiyavtonomnyy okrug\",\n \"RU-YAR\": \"Yaroslavskaya oblast'\",\n \"RU-YEV\": \"Yevreyskaya avtonomnaya oblast'\",\n \"RU-ZAB\": \"Zabaykal'skiy kray\",\n \"RW-01\": \"City of Kigali\",\n \"RW-02\": \"Eastern\",\n \"RW-03\": \"Northern\",\n \"RW-05\": \"Southern\",\n \"RW-04\": \"Western\",\n \"SH-AC\": \"Ascension\",\n \"SH-HL\": \"Saint Helena\",\n \"SH-TA\": \"Tristan da Cunha\",\n \"KN-K\": \"Saint Kitts\",\n \"KN-N\": \"Nevis\",\n \"LC-01\": \"Anse la Raye\",\n \"LC-12\": \"Canaries\",\n \"LC-02\": \"Castries\",\n \"LC-03\": \"Choiseul\",\n \"LC-05\": \"Dennery\",\n \"LC-06\": \"Gros Islet\",\n \"LC-07\": \"Laborie\",\n \"LC-08\": \"Micoud\",\n \"LC-10\": \"Soufrière\",\n \"LC-11\": \"Vieux Fort\",\n \"VC-01\": \"Charlotte\",\n \"VC-06\": \"Grenadines\",\n \"VC-02\": \"Saint Andrew\",\n \"VC-03\": \"Saint David\",\n \"VC-04\": \"Saint George\",\n \"VC-05\": \"Saint Patrick\",\n \"WS-AA\": \"A'ana\",\n \"WS-AL\": \"Aiga-i-le-Tai\",\n \"WS-AT\": \"Atua\",\n \"WS-FA\": \"Fa'asaleleaga\",\n \"WS-GE\": \"Gaga'emauga\",\n \"WS-GI\": \"Gagaifomauga\",\n \"WS-PA\": \"Palauli\",\n \"WS-SA\": \"Satupa'itea\",\n \"WS-TU\": \"Tuamasaga\",\n \"WS-VF\": \"Va'a-o-Fonoti\",\n \"WS-VS\": \"Vaisigano\",\n \"SM-01\": \"Acquaviva\",\n \"SM-06\": \"Borgo Maggiore\",\n \"SM-02\": \"Chiesanuova\",\n \"SM-07\": \"Città di San Marino\",\n \"SM-03\": \"Domagnano\",\n \"SM-04\": \"Faetano\",\n \"SM-05\": \"Fiorentino\",\n \"SM-08\": \"Montegiardino\",\n \"SM-09\": \"Serravalle\",\n \"ST-01\": \"Água Grande\",\n \"ST-02\": \"Cantagalo\",\n \"ST-03\": \"Caué\",\n \"ST-04\": \"Lembá\",\n \"ST-05\": \"Lobata\",\n \"ST-06\": \"Mé-Zóchi\",\n \"ST-P\": \"Príncipe\",\n \"SA-14\": \"'Asīr\",\n \"SA-11\": \"Al Bāḩah\",\n \"SA-08\": \"Al Ḩudūd ash Shamālīyah\",\n \"SA-12\": \"Al Jawf\",\n \"SA-03\": \"Al Madīnah al Munawwarah\",\n \"SA-05\": \"Al Qaşīm\",\n \"SA-01\": \"Ar Riyāḑ\",\n \"SA-04\": \"Ash Sharqīyah\",\n \"SA-06\": \"Ḩā'il\",\n \"SA-09\": \"Jāzān\",\n \"SA-02\": \"Makkah al Mukarramah\",\n \"SA-10\": \"Najrān\",\n \"SA-07\": \"Tabūk\",\n \"SN-DK\": \"Dakar\",\n \"SN-DB\": \"Diourbel\",\n \"SN-FK\": \"Fatick\",\n \"SN-KA\": \"Kaffrine\",\n \"SN-KL\": \"Kaolack\",\n \"SN-KE\": \"Kédougou\",\n \"SN-KD\": \"Kolda\",\n \"SN-LG\": \"Louga\",\n \"SN-MT\": \"Matam\",\n \"SN-SL\": \"Saint-Louis\",\n \"SN-SE\": \"Sédhiou\",\n \"SN-TC\": \"Tambacounda\",\n \"SN-TH\": \"Thiès\",\n \"SN-ZG\": \"Ziguinchor\",\n \"SC-01\": \"Anse aux Pins\",\n \"SC-02\": \"Anse Boileau\",\n \"SC-03\": \"Anse Etoile\",\n \"SC-05\": \"Anse Royale\",\n \"SC-04\": \"Au Cap\",\n \"SC-06\": \"Baie Lazare\",\n \"SC-07\": \"Baie Sainte Anne\",\n \"SC-08\": \"Beau Vallon\",\n \"SC-09\": \"Bel Air\",\n \"SC-10\": \"Bel Ombre\",\n \"SC-11\": \"Cascade\",\n \"SC-16\": \"English River\",\n \"SC-12\": \"Glacis\",\n \"SC-13\": \"Grand Anse Mahe\",\n \"SC-14\": \"Grand Anse Praslin\",\n \"SC-26\": \"Ile Perseverance I\",\n \"SC-27\": \"Ile Perseverance II\",\n \"SC-15\": \"La Digue\",\n \"SC-24\": \"Les Mamelles\",\n \"SC-17\": \"Mont Buxton\",\n \"SC-18\": \"Mont Fleuri\",\n \"SC-19\": \"Plaisance\",\n \"SC-20\": \"Pointe Larue\",\n \"SC-21\": \"Port Glaud\",\n \"SC-25\": \"Roche Caiman\",\n \"SC-22\": \"Saint Louis\",\n \"SC-23\": \"Takamaka\",\n \"SL-E\": \"Eastern\",\n \"SL-NW\": \"North Western\",\n \"SL-N\": \"Northern\",\n \"SL-S\": \"Southern\",\n \"SL-W\": \"Western Area\",\n \"SG-01\": \"Central Singapore\",\n \"SG-02\": \"North East\",\n \"SG-03\": \"North West\",\n \"SG-04\": \"South East\",\n \"SG-05\": \"South West\",\n \"SK-BC\": \"Banskobystrický kraj\",\n \"SK-BL\": \"Bratislavský kraj\",\n \"SK-KI\": \"Košický kraj\",\n \"SK-NI\": \"Nitriansky kraj\",\n \"SK-PV\": \"Prešovský kraj\",\n \"SK-TC\": \"Trenčiansky kraj\",\n \"SK-TA\": \"Trnavský kraj\",\n \"SK-ZI\": \"Žilinský kraj\",\n \"SI-001\": \"Ajdovščina\",\n \"SI-213\": \"Ankaran\",\n \"SI-195\": \"Apače\",\n \"SI-002\": \"Beltinci\",\n \"SI-148\": \"Benedikt\",\n \"SI-149\": \"Bistrica ob Sotli\",\n \"SI-003\": \"Bled\",\n \"SI-150\": \"Bloke\",\n \"SI-004\": \"Bohinj\",\n \"SI-005\": \"Borovnica\",\n \"SI-006\": \"Bovec\",\n \"SI-151\": \"Braslovče\",\n \"SI-007\": \"Brda\",\n \"SI-008\": \"Brezovica\",\n \"SI-009\": \"Brežice\",\n \"SI-152\": \"Cankova\",\n \"SI-011\": \"Celje\",\n \"SI-012\": \"Cerklje na Gorenjskem\",\n \"SI-013\": \"Cerknica\",\n \"SI-014\": \"Cerkno\",\n \"SI-153\": \"Cerkvenjak\",\n \"SI-196\": \"Cirkulane\",\n \"SI-015\": \"Črenšovci\",\n \"SI-016\": \"Črna na Koroškem\",\n \"SI-017\": \"Črnomelj\",\n \"SI-018\": \"Destrnik\",\n \"SI-019\": \"Divača\",\n \"SI-154\": \"Dobje\",\n \"SI-020\": \"Dobrepolje\",\n \"SI-155\": \"Dobrna\",\n \"SI-021\": \"Dobrova-Polhov Gradec\",\n \"SI-156\": \"Dobrovnik\",\n \"SI-022\": \"Dol pri Ljubljani\",\n \"SI-157\": \"Dolenjske Toplice\",\n \"SI-023\": \"Domžale\",\n \"SI-024\": \"Dornava\",\n \"SI-025\": \"Dravograd\",\n \"SI-026\": \"Duplek\",\n \"SI-027\": \"Gorenja vas-Poljane\",\n \"SI-028\": \"Gorišnica\",\n \"SI-207\": \"Gorje\",\n \"SI-029\": \"Gornja Radgona\",\n \"SI-030\": \"Gornji Grad\",\n \"SI-031\": \"Gornji Petrovci\",\n \"SI-158\": \"Grad\",\n \"SI-032\": \"Grosuplje\",\n \"SI-159\": \"Hajdina\",\n \"SI-160\": \"Hoče-Slivnica\",\n \"SI-161\": \"Hodoš\",\n \"SI-162\": \"Horjul\",\n \"SI-034\": \"Hrastnik\",\n \"SI-035\": \"Hrpelje-Kozina\",\n \"SI-036\": \"Idrija\",\n \"SI-037\": \"Ig\",\n \"SI-038\": \"Ilirska Bistrica\",\n \"SI-039\": \"Ivančna Gorica\",\n \"SI-040\": \"Izola\",\n \"SI-041\": \"Jesenice\",\n \"SI-163\": \"Jezersko\",\n \"SI-042\": \"Juršinci\",\n \"SI-043\": \"Kamnik\",\n \"SI-044\": \"Kanal ob Soči\",\n \"SI-045\": \"Kidričevo\",\n \"SI-046\": \"Kobarid\",\n \"SI-047\": \"Kobilje\",\n \"SI-048\": \"Kočevje\",\n \"SI-049\": \"Komen\",\n \"SI-164\": \"Komenda\",\n \"SI-050\": \"Koper\",\n \"SI-197\": \"Kostanjevica na Krki\",\n \"SI-165\": \"Kostel\",\n \"SI-051\": \"Kozje\",\n \"SI-052\": \"Kranj\",\n \"SI-053\": \"Kranjska Gora\",\n \"SI-166\": \"Križevci\",\n \"SI-054\": \"Krško\",\n \"SI-055\": \"Kungota\",\n \"SI-056\": \"Kuzma\",\n \"SI-057\": \"Laško\",\n \"SI-058\": \"Lenart\",\n \"SI-059\": \"Lendava\",\n \"SI-060\": \"Litija\",\n \"SI-061\": \"Ljubljana\",\n \"SI-062\": \"Ljubno\",\n \"SI-063\": \"Ljutomer\",\n \"SI-208\": \"Log-Dragomer\",\n \"SI-064\": \"Logatec\",\n \"SI-065\": \"Loška dolina\",\n \"SI-066\": \"Loški Potok\",\n \"SI-167\": \"Lovrenc na Pohorju\",\n \"SI-067\": \"Luče\",\n \"SI-068\": \"Lukovica\",\n \"SI-069\": \"Majšperk\",\n \"SI-198\": \"Makole\",\n \"SI-070\": \"Maribor\",\n \"SI-168\": \"Markovci\",\n \"SI-071\": \"Medvode\",\n \"SI-072\": \"Mengeš\",\n \"SI-073\": \"Metlika\",\n \"SI-074\": \"Mežica\",\n \"SI-169\": \"Miklavž na Dravskem polju\",\n \"SI-075\": \"Miren-Kostanjevica\",\n \"SI-212\": \"Mirna\",\n \"SI-170\": \"Mirna Peč\",\n \"SI-076\": \"Mislinja\",\n \"SI-199\": \"Mokronog-Trebelno\",\n \"SI-077\": \"Moravče\",\n \"SI-078\": \"Moravske Toplice\",\n \"SI-079\": \"Mozirje\",\n \"SI-080\": \"Murska Sobota\",\n \"SI-081\": \"Muta\",\n \"SI-082\": \"Naklo\",\n \"SI-083\": \"Nazarje\",\n \"SI-084\": \"Nova Gorica\",\n \"SI-085\": \"Novo Mesto\",\n \"SI-086\": \"Odranci\",\n \"SI-171\": \"Oplotnica\",\n \"SI-087\": \"Ormož\",\n \"SI-088\": \"Osilnica\",\n \"SI-089\": \"Pesnica\",\n \"SI-090\": \"Piran\",\n \"SI-091\": \"Pivka\",\n \"SI-092\": \"Podčetrtek\",\n \"SI-172\": \"Podlehnik\",\n \"SI-093\": \"Podvelka\",\n \"SI-200\": \"Poljčane\",\n \"SI-173\": \"Polzela\",\n \"SI-094\": \"Postojna\",\n \"SI-174\": \"Prebold\",\n \"SI-095\": \"Preddvor\",\n \"SI-175\": \"Prevalje\",\n \"SI-096\": \"Ptuj\",\n \"SI-097\": \"Puconci\",\n \"SI-098\": \"Rače-Fram\",\n \"SI-099\": \"Radeče\",\n \"SI-100\": \"Radenci\",\n \"SI-101\": \"Radlje ob Dravi\",\n \"SI-102\": \"Radovljica\",\n \"SI-103\": \"Ravne na Koroškem\",\n \"SI-176\": \"Razkrižje\",\n \"SI-209\": \"Rečica ob Savinji\",\n \"SI-201\": \"Renče-Vogrsko\",\n \"SI-104\": \"Ribnica\",\n \"SI-177\": \"Ribnica na Pohorju\",\n \"SI-106\": \"Rogaška Slatina\",\n \"SI-105\": \"Rogašovci\",\n \"SI-107\": \"Rogatec\",\n \"SI-108\": \"Ruše\",\n \"SI-178\": \"Selnica ob Dravi\",\n \"SI-109\": \"Semič\",\n \"SI-110\": \"Sevnica\",\n \"SI-111\": \"Sežana\",\n \"SI-112\": \"Slovenj Gradec\",\n \"SI-113\": \"Slovenska Bistrica\",\n \"SI-114\": \"Slovenske Konjice\",\n \"SI-179\": \"Sodražica\",\n \"SI-180\": \"Solčava\",\n \"SI-202\": \"Središče ob Dravi\",\n \"SI-115\": \"Starše\",\n \"SI-203\": \"Straža\",\n \"SI-181\": \"Sveta Ana\",\n \"SI-204\": \"Sveta Trojica v Slovenskih goricah\",\n \"SI-182\": \"Sveti Andraž v Slovenskih goricah\",\n \"SI-116\": \"Sveti Jurij ob Ščavnici\",\n \"SI-210\": \"Sveti Jurij v Slovenskih goricah\",\n \"SI-205\": \"Sveti Tomaž\",\n \"SI-033\": \"Šalovci\",\n \"SI-183\": \"Šempeter-Vrtojba\",\n \"SI-117\": \"Šenčur\",\n \"SI-118\": \"Šentilj\",\n \"SI-119\": \"Šentjernej\",\n \"SI-120\": \"Šentjur\",\n \"SI-211\": \"Šentrupert\",\n \"SI-121\": \"Škocjan\",\n \"SI-122\": \"Škofja Loka\",\n \"SI-123\": \"Škofljica\",\n \"SI-124\": \"Šmarje pri Jelšah\",\n \"SI-206\": \"Šmarješke Toplice\",\n \"SI-125\": \"Šmartno ob Paki\",\n \"SI-194\": \"Šmartno pri Litiji\",\n \"SI-126\": \"Šoštanj\",\n \"SI-127\": \"Štore\",\n \"SI-184\": \"Tabor\",\n \"SI-010\": \"Tišina\",\n \"SI-128\": \"Tolmin\",\n \"SI-129\": \"Trbovlje\",\n \"SI-130\": \"Trebnje\",\n \"SI-185\": \"Trnovska Vas\",\n \"SI-186\": \"Trzin\",\n \"SI-131\": \"Tržič\",\n \"SI-132\": \"Turnišče\",\n \"SI-133\": \"Velenje\",\n \"SI-187\": \"Velika Polana\",\n \"SI-134\": \"Velike Lašče\",\n \"SI-188\": \"Veržej\",\n \"SI-135\": \"Videm\",\n \"SI-136\": \"Vipava\",\n \"SI-137\": \"Vitanje\",\n \"SI-138\": \"Vodice\",\n \"SI-139\": \"Vojnik\",\n \"SI-189\": \"Vransko\",\n \"SI-140\": \"Vrhnika\",\n \"SI-141\": \"Vuzenica\",\n \"SI-142\": \"Zagorje ob Savi\",\n \"SI-143\": \"Zavrč\",\n \"SI-144\": \"Zreče\",\n \"SI-190\": \"Žalec\",\n \"SI-146\": \"Železniki\",\n \"SI-191\": \"Žetale\",\n \"SI-147\": \"Žiri\",\n \"SI-192\": \"Žirovnica\",\n \"SI-193\": \"Žužemberk\",\n \"SB-CT\": \"Capital Territory\",\n \"SB-CE\": \"Central\",\n \"SB-CH\": \"Choiseul\",\n \"SB-GU\": \"Guadalcanal\",\n \"SB-IS\": \"Isabel\",\n \"SB-MK\": \"Makira-Ulawa\",\n \"SB-ML\": \"Malaita\",\n \"SB-RB\": \"Rennell and Bellona\",\n \"SB-TE\": \"Temotu\",\n \"SB-WE\": \"Western\",\n \"SO-AW\": \"Awdal\",\n \"SO-BK\": \"Bakool\",\n \"SO-BN\": \"Banaadir\",\n \"SO-BR\": \"Bari\",\n \"SO-BY\": \"Bay\",\n \"SO-GA\": \"Galguduud\",\n \"SO-GE\": \"Gedo\",\n \"SO-HI\": \"Hiiraan\",\n \"SO-JD\": \"Jubbada Dhexe\",\n \"SO-JH\": \"Jubbada Hoose\",\n \"SO-MU\": \"Mudug\",\n \"SO-NU\": \"Nugaal\",\n \"SO-SA\": \"Sanaag\",\n \"SO-SD\": \"Shabeellaha Dhexe\",\n \"SO-SH\": \"Shabeellaha Hoose\",\n \"SO-SO\": \"Sool\",\n \"SO-TO\": \"Togdheer\",\n \"SO-WO\": \"Woqooyi Galbeed\",\n \"ZA-EC\": \"Eastern Cape\",\n \"ZA-FS\": \"Free State\",\n \"ZA-GP\": \"Gauteng\",\n \"ZA-KZN\": \"Kwazulu-Natal\",\n \"ZA-LP\": \"Limpopo\",\n \"ZA-MP\": \"Mpumalanga\",\n \"ZA-NW\": \"North-West\",\n \"ZA-NC\": \"Northern Cape\",\n \"ZA-WC\": \"Western Cape\",\n \"ES-AN\": \"Andalucía\",\n \"ES-AR\": \"Aragón\",\n \"ES-AS\": \"Asturias\",\n \"ES-CN\": \"Canarias\",\n \"ES-CB\": \"Cantabria\",\n \"ES-CL\": \"Castilla y León\",\n \"ES-CM\": \"Castilla-La Mancha\",\n \"ES-CT\": \"Catalunya\",\n \"ES-CE\": \"Ceuta\",\n \"ES-EX\": \"Extremadura\",\n \"ES-GA\": \"Galicia\",\n \"ES-IB\": \"Illes Balears\",\n \"ES-RI\": \"La Rioja\",\n \"ES-MD\": \"Madrid\",\n \"ES-ML\": \"Melilla\",\n \"ES-MC\": \"Murcia\",\n \"ES-NC\": \"Navarra\",\n \"ES-PV\": \"País Vasco\",\n \"ES-VC\": \"Valenciana\",\n \"LK-1\": \"Basnāhira paḷāta\",\n \"LK-3\": \"Dakuṇu paḷāta\",\n \"LK-2\": \"Madhyama paḷāta\",\n \"LK-5\": \"Næ̆gĕnahira paḷāta\",\n \"LK-9\": \"Sabaragamuva paḷāta\",\n \"LK-4\": \"Uturu paḷāta\",\n \"LK-7\": \"Uturumæ̆da paḷāta\",\n \"LK-8\": \"Ūva paḷāta\",\n \"LK-6\": \"Vayamba paḷāta\",\n \"SD-RS\": \"Al Baḩr al Aḩmar\",\n \"SD-GZ\": \"Al Jazīrah\",\n \"SD-KH\": \"Al Kharţūm\",\n \"SD-GD\": \"Al Qaḑārif\",\n \"SD-NW\": \"An Nīl al Abyaḑ\",\n \"SD-NB\": \"An Nīl al Azraq\",\n \"SD-NO\": \"Ash Shamālīyah\",\n \"SD-DW\": \"Gharb Dārfūr\",\n \"SD-GK\": \"Gharb Kurdufān\",\n \"SD-DS\": \"Janūb Dārfūr\",\n \"SD-KS\": \"Janūb Kurdufān\",\n \"SD-KA\": \"Kassalā\",\n \"SD-NR\": \"Nahr an Nīl\",\n \"SD-DN\": \"Shamāl Dārfūr\",\n \"SD-KN\": \"Shamāl Kurdufān\",\n \"SD-DE\": \"Sharq Dārfūr\",\n \"SD-SI\": \"Sinnār\",\n \"SD-DC\": \"Wasaţ Dārfūr\",\n \"SR-BR\": \"Brokopondo\",\n \"SR-CM\": \"Commewijne\",\n \"SR-CR\": \"Coronie\",\n \"SR-MA\": \"Marowijne\",\n \"SR-NI\": \"Nickerie\",\n \"SR-PR\": \"Para\",\n \"SR-PM\": \"Paramaribo\",\n \"SR-SA\": \"Saramacca\",\n \"SR-SI\": \"Sipaliwini\",\n \"SR-WA\": \"Wanica\",\n \"SZ-HH\": \"Hhohho\",\n \"SZ-LU\": \"Lubombo\",\n \"SZ-MA\": \"Manzini\",\n \"SZ-SH\": \"Shiselweni\",\n \"SE-K\": \"Blekinge län\",\n \"SE-W\": \"Dalarnas län\",\n \"SE-I\": \"Gotlands län\",\n \"SE-X\": \"Gävleborgs län\",\n \"SE-N\": \"Hallands län\",\n \"SE-Z\": \"Jämtlands län\",\n \"SE-F\": \"Jönköpings län\",\n \"SE-H\": \"Kalmar län\",\n \"SE-G\": \"Kronobergs län\",\n \"SE-BD\": \"Norrbottens län\",\n \"SE-M\": \"Skåne län\",\n \"SE-AB\": \"Stockholms län\",\n \"SE-D\": \"Södermanlands län\",\n \"SE-C\": \"Uppsala län\",\n \"SE-S\": \"Värmlands län\",\n \"SE-AC\": \"Västerbottens län\",\n \"SE-Y\": \"Västernorrlands län\",\n \"SE-U\": \"Västmanlands län\",\n \"SE-O\": \"Västra Götalands län\",\n \"SE-T\": \"Örebro län\",\n \"SE-E\": \"Östergötlands län\",\n \"CH-AG\": \"Aargau\",\n \"CH-AR\": \"Appenzell Ausserrhoden\",\n \"CH-AI\": \"Appenzell Innerrhoden\",\n \"CH-BL\": \"Basel-Landschaft\",\n \"CH-BS\": \"Basel-Stadt\",\n \"CH-BE\": \"Bern\",\n \"CH-FR\": \"Fribourg\",\n \"CH-GE\": \"Genève\",\n \"CH-GL\": \"Glarus\",\n \"CH-GR\": \"Graubünden\",\n \"CH-JU\": \"Jura\",\n \"CH-LU\": \"Luzern\",\n \"CH-NE\": \"Neuchâtel\",\n \"CH-NW\": \"Nidwalden\",\n \"CH-OW\": \"Obwalden\",\n \"CH-SG\": \"Sankt Gallen\",\n \"CH-SH\": \"Schaffhausen\",\n \"CH-SZ\": \"Schwyz\",\n \"CH-SO\": \"Solothurn\",\n \"CH-TG\": \"Thurgau\",\n \"CH-TI\": \"Ticino\",\n \"CH-UR\": \"Uri\",\n \"CH-VS\": \"Valais\",\n \"CH-VD\": \"Vaud\",\n \"CH-ZG\": \"Zug\",\n \"CH-ZH\": \"Zürich\",\n \"SY-HA\": \"Al Ḩasakah\",\n \"SY-LA\": \"Al Lādhiqīyah\",\n \"SY-QU\": \"Al Qunayţirah\",\n \"SY-RA\": \"Ar Raqqah\",\n \"SY-SU\": \"As Suwaydā'\",\n \"SY-DR\": \"Dar'ā\",\n \"SY-DY\": \"Dayr az Zawr\",\n \"SY-DI\": \"Dimashq\",\n \"SY-HL\": \"Ḩalab\",\n \"SY-HM\": \"Ḩamāh\",\n \"SY-HI\": \"Ḩimş\",\n \"SY-ID\": \"Idlib\",\n \"SY-RD\": \"Rīf Dimashq\",\n \"SY-TA\": \"Ţarţūs\",\n \"TW-CHA\": \"Changhua\",\n \"TW-CYI\": \"Chiayi\",\n \"TW-CYQ\": \"Chiayi\",\n \"TW-HSZ\": \"Hsinchu\",\n \"TW-HSQ\": \"Hsinchu\",\n \"TW-HUA\": \"Hualien\",\n \"TW-KHH\": \"Kaohsiung\",\n \"TW-KEE\": \"Keelung\",\n \"TW-KIN\": \"Kinmen\",\n \"TW-LIE\": \"Lienchiang\",\n \"TW-MIA\": \"Miaoli\",\n \"TW-NAN\": \"Nantou\",\n \"TW-NWT\": \"New Taipei\",\n \"TW-PEN\": \"Penghu\",\n \"TW-PIF\": \"Pingtung\",\n \"TW-TXG\": \"Taichung\",\n \"TW-TNN\": \"Tainan\",\n \"TW-TPE\": \"Taipei\",\n \"TW-TTT\": \"Taitung\",\n \"TW-TAO\": \"Taoyuan\",\n \"TW-ILA\": \"Yilan\",\n \"TW-YUN\": \"Yunlin\",\n \"TJ-DU\": \"Dushanbe\",\n \"TJ-KT\": \"Khatlon\",\n \"TJ-GB\": \"Kŭhistoni Badakhshon\",\n \"TJ-RA\": \"nohiyahoi tobei jumhurí\",\n \"TJ-SU\": \"Sughd\",\n \"TZ-01\": \"Arusha\",\n \"TZ-02\": \"Dar es Salaam\",\n \"TZ-03\": \"Dodoma\",\n \"TZ-27\": \"Geita\",\n \"TZ-04\": \"Iringa\",\n \"TZ-05\": \"Kagera\",\n \"TZ-06\": \"Kaskazini Pemba\",\n \"TZ-07\": \"Kaskazini Unguja\",\n \"TZ-28\": \"Katavi\",\n \"TZ-08\": \"Kigoma\",\n \"TZ-09\": \"Kilimanjaro\",\n \"TZ-10\": \"Kusini Pemba\",\n \"TZ-11\": \"Kusini Unguja\",\n \"TZ-12\": \"Lindi\",\n \"TZ-26\": \"Manyara\",\n \"TZ-13\": \"Mara\",\n \"TZ-14\": \"Mbeya\",\n \"TZ-15\": \"Mjini Magharibi\",\n \"TZ-16\": \"Morogoro\",\n \"TZ-17\": \"Mtwara\",\n \"TZ-18\": \"Mwanza\",\n \"TZ-29\": \"Njombe\",\n \"TZ-19\": \"Pwani\",\n \"TZ-20\": \"Rukwa\",\n \"TZ-21\": \"Ruvuma\",\n \"TZ-22\": \"Shinyanga\",\n \"TZ-30\": \"Simiyu\",\n \"TZ-23\": \"Singida\",\n \"TZ-31\": \"Songwe\",\n \"TZ-24\": \"Tabora\",\n \"TZ-25\": \"Tanga\",\n \"TH-37\": \"Amnat Charoen\",\n \"TH-15\": \"Ang Thong\",\n \"TH-38\": \"Bueng Kan\",\n \"TH-31\": \"Buri Ram\",\n \"TH-24\": \"Chachoengsao\",\n \"TH-18\": \"Chai Nat\",\n \"TH-36\": \"Chaiyaphum\",\n \"TH-22\": \"Chanthaburi\",\n \"TH-50\": \"Chiang Mai\",\n \"TH-57\": \"Chiang Rai\",\n \"TH-20\": \"Chon Buri\",\n \"TH-86\": \"Chumphon\",\n \"TH-46\": \"Kalasin\",\n \"TH-62\": \"Kamphaeng Phet\",\n \"TH-71\": \"Kanchanaburi\",\n \"TH-40\": \"Khon Kaen\",\n \"TH-81\": \"Krabi\",\n \"TH-10\": \"Bangkok\",\n \"TH-52\": \"Lampang\",\n \"TH-51\": \"Lamphun\",\n \"TH-42\": \"Loei\",\n \"TH-16\": \"Lop Buri\",\n \"TH-58\": \"Mae Hong Son\",\n \"TH-44\": \"Maha Sarakham\",\n \"TH-49\": \"Mukdahan\",\n \"TH-26\": \"Nakhon Nayok\",\n \"TH-73\": \"Nakhon Pathom\",\n \"TH-48\": \"Nakhon Phanom\",\n \"TH-30\": \"Nakhon Ratchasima\",\n \"TH-60\": \"Nakhon Sawan\",\n \"TH-80\": \"Nakhon Si Thammarat\",\n \"TH-55\": \"Nan\",\n \"TH-96\": \"Narathiwat\",\n \"TH-39\": \"Nong Bua Lam Phu\",\n \"TH-43\": \"Nong Khai\",\n \"TH-12\": \"Nonthaburi\",\n \"TH-13\": \"Pathum Thani\",\n \"TH-94\": \"Pattani\",\n \"TH-82\": \"Phangnga\",\n \"TH-93\": \"Phatthalung\",\n \"TH-S\": \"Phatthaya\",\n \"TH-56\": \"Phayao\",\n \"TH-67\": \"Phetchabun\",\n \"TH-76\": \"Phetchaburi\",\n \"TH-66\": \"Phichit\",\n \"TH-65\": \"Phitsanulok\",\n \"TH-14\": \"Phra Nakhon Si Ayutthaya\",\n \"TH-54\": \"Phrae\",\n \"TH-83\": \"Phuket\",\n \"TH-25\": \"Prachin Buri\",\n \"TH-77\": \"Prachuap Khiri Khan\",\n \"TH-85\": \"Ranong\",\n \"TH-70\": \"Ratchaburi\",\n \"TH-21\": \"Rayong\",\n \"TH-45\": \"Roi Et\",\n \"TH-27\": \"Sa Kaeo\",\n \"TH-47\": \"Sakon Nakhon\",\n \"TH-11\": \"Samut Prakan\",\n \"TH-74\": \"Samut Sakhon\",\n \"TH-75\": \"Samut Songkhram\",\n \"TH-19\": \"Saraburi\",\n \"TH-91\": \"Satun\",\n \"TH-33\": \"Si Sa Ket\",\n \"TH-17\": \"Sing Buri\",\n \"TH-90\": \"Songkhla\",\n \"TH-64\": \"Sukhothai\",\n \"TH-72\": \"Suphan Buri\",\n \"TH-84\": \"Surat Thani\",\n \"TH-32\": \"Surin\",\n \"TH-63\": \"Tak\",\n \"TH-92\": \"Trang\",\n \"TH-23\": \"Trat\",\n \"TH-34\": \"Ubon Ratchathani\",\n \"TH-41\": \"Udon Thani\",\n \"TH-61\": \"Uthai Thani\",\n \"TH-53\": \"Uttaradit\",\n \"TH-95\": \"Yala\",\n \"TH-35\": \"Yasothon\",\n \"TL-AL\": \"Aileu\",\n \"TL-AN\": \"Ainaro\",\n \"TL-BA\": \"Baucau\",\n \"TL-BO\": \"Bobonaro\",\n \"TL-CO\": \"Cova Lima\",\n \"TL-DI\": \"Díli\",\n \"TL-ER\": \"Ermera\",\n \"TL-LA\": \"Lautém\",\n \"TL-LI\": \"Liquiça\",\n \"TL-MT\": \"Manatuto\",\n \"TL-MF\": \"Manufahi\",\n \"TL-OE\": \"Oé-Cusse Ambeno\",\n \"TL-VI\": \"Viqueque\",\n \"TG-C\": \"Centrale\",\n \"TG-K\": \"Kara\",\n \"TG-M\": \"Maritime\",\n \"TG-P\": \"Plateaux\",\n \"TG-S\": \"Savanes\",\n \"TO-01\": \"'Eua\",\n \"TO-02\": \"Ha'apai\",\n \"TO-03\": \"Niuas\",\n \"TO-04\": \"Tongatapu\",\n \"TO-05\": \"Vava'u\",\n \"TT-ARI\": \"Arima\",\n \"TT-CHA\": \"Chaguanas\",\n \"TT-CTT\": \"Couva-Tabaquite-Talparo\",\n \"TT-DMN\": \"Diego Martin\",\n \"TT-MRC\": \"Mayaro-Rio Claro\",\n \"TT-PED\": \"Penal-Debe\",\n \"TT-POS\": \"Port of Spain\",\n \"TT-PRT\": \"Princes Town\",\n \"TT-PTF\": \"Point Fortin\",\n \"TT-SFO\": \"San Fernando\",\n \"TT-SGE\": \"Sangre Grande\",\n \"TT-SIP\": \"Siparia\",\n \"TT-SJL\": \"San Juan-Laventille\",\n \"TT-TOB\": \"Tobago\",\n \"TT-TUP\": \"Tunapuna-Piarco\",\n \"TN-31\": \"Béja\",\n \"TN-13\": \"Ben Arous\",\n \"TN-23\": \"Bizerte\",\n \"TN-81\": \"Gabès\",\n \"TN-71\": \"Gafsa\",\n \"TN-32\": \"Jendouba\",\n \"TN-41\": \"Kairouan\",\n \"TN-42\": \"Kasserine\",\n \"TN-73\": \"Kébili\",\n \"TN-12\": \"L'Ariana\",\n \"TN-14\": \"La Manouba\",\n \"TN-33\": \"Le Kef\",\n \"TN-53\": \"Mahdia\",\n \"TN-82\": \"Médenine\",\n \"TN-52\": \"Monastir\",\n \"TN-21\": \"Nabeul\",\n \"TN-61\": \"Sfax\",\n \"TN-43\": \"Sidi Bouzid\",\n \"TN-34\": \"Siliana\",\n \"TN-51\": \"Sousse\",\n \"TN-83\": \"Tataouine\",\n \"TN-72\": \"Tozeur\",\n \"TN-11\": \"Tunis\",\n \"TN-22\": \"Zaghouan\",\n \"TR-01\": \"Adana\",\n \"TR-02\": \"Adıyaman\",\n \"TR-03\": \"Afyonkarahisar\",\n \"TR-04\": \"Ağrı\",\n \"TR-68\": \"Aksaray\",\n \"TR-05\": \"Amasya\",\n \"TR-06\": \"Ankara\",\n \"TR-07\": \"Antalya\",\n \"TR-75\": \"Ardahan\",\n \"TR-08\": \"Artvin\",\n \"TR-09\": \"Aydın\",\n \"TR-10\": \"Balıkesir\",\n \"TR-74\": \"Bartın\",\n \"TR-72\": \"Batman\",\n \"TR-69\": \"Bayburt\",\n \"TR-11\": \"Bilecik\",\n \"TR-12\": \"Bingöl\",\n \"TR-13\": \"Bitlis\",\n \"TR-14\": \"Bolu\",\n \"TR-15\": \"Burdur\",\n \"TR-16\": \"Bursa\",\n \"TR-17\": \"Çanakkale\",\n \"TR-18\": \"Çankırı\",\n \"TR-19\": \"Çorum\",\n \"TR-20\": \"Denizli\",\n \"TR-21\": \"Diyarbakır\",\n \"TR-81\": \"Düzce\",\n \"TR-22\": \"Edirne\",\n \"TR-23\": \"Elazığ\",\n \"TR-24\": \"Erzincan\",\n \"TR-25\": \"Erzurum\",\n \"TR-26\": \"Eskişehir\",\n \"TR-27\": \"Gaziantep\",\n \"TR-28\": \"Giresun\",\n \"TR-29\": \"Gümüşhane\",\n \"TR-30\": \"Hakkâri\",\n \"TR-31\": \"Hatay\",\n \"TR-76\": \"Iğdır\",\n \"TR-32\": \"Isparta\",\n \"TR-34\": \"İstanbul\",\n \"TR-35\": \"İzmir\",\n \"TR-46\": \"Kahramanmaraş\",\n \"TR-78\": \"Karabük\",\n \"TR-70\": \"Karaman\",\n \"TR-36\": \"Kars\",\n \"TR-37\": \"Kastamonu\",\n \"TR-38\": \"Kayseri\",\n \"TR-71\": \"Kırıkkale\",\n \"TR-39\": \"Kırklareli\",\n \"TR-40\": \"Kırşehir\",\n \"TR-79\": \"Kilis\",\n \"TR-41\": \"Kocaeli\",\n \"TR-42\": \"Konya\",\n \"TR-43\": \"Kütahya\",\n \"TR-44\": \"Malatya\",\n \"TR-45\": \"Manisa\",\n \"TR-47\": \"Mardin\",\n \"TR-33\": \"Mersin\",\n \"TR-48\": \"Muğla\",\n \"TR-49\": \"Muş\",\n \"TR-50\": \"Nevşehir\",\n \"TR-51\": \"Niğde\",\n \"TR-52\": \"Ordu\",\n \"TR-80\": \"Osmaniye\",\n \"TR-53\": \"Rize\",\n \"TR-54\": \"Sakarya\",\n \"TR-55\": \"Samsun\",\n \"TR-56\": \"Siirt\",\n \"TR-57\": \"Sinop\",\n \"TR-58\": \"Sivas\",\n \"TR-63\": \"Şanlıurfa\",\n \"TR-73\": \"Şırnak\",\n \"TR-59\": \"Tekirdağ\",\n \"TR-60\": \"Tokat\",\n \"TR-61\": \"Trabzon\",\n \"TR-62\": \"Tunceli\",\n \"TR-64\": \"Uşak\",\n \"TR-65\": \"Van\",\n \"TR-77\": \"Yalova\",\n \"TR-66\": \"Yozgat\",\n \"TR-67\": \"Zonguldak\",\n \"TM-A\": \"Ahal\",\n \"TM-S\": \"Aşgabat\",\n \"TM-B\": \"Balkan\",\n \"TM-D\": \"Daşoguz\",\n \"TM-L\": \"Lebap\",\n \"TM-M\": \"Mary\",\n \"TV-FUN\": \"Funafuti\",\n \"TV-NMG\": \"Nanumaga\",\n \"TV-NMA\": \"Nanumea\",\n \"TV-NIT\": \"Niutao\",\n \"TV-NUI\": \"Nui\",\n \"TV-NKF\": \"Nukufetau\",\n \"TV-NKL\": \"Nukulaelae\",\n \"TV-VAI\": \"Vaitupu\",\n \"UG-C\": \"Central\",\n \"UG-E\": \"Eastern\",\n \"UG-N\": \"Northern\",\n \"UG-W\": \"Western\",\n \"UA-43\": \"Avtonomna Respublika Krym\",\n \"UA-71\": \"Cherkaska oblast\",\n \"UA-74\": \"Chernihivska oblast\",\n \"UA-77\": \"Chernivetska oblast\",\n \"UA-12\": \"Dnipropetrovska oblast\",\n \"UA-14\": \"Donetska oblast\",\n \"UA-26\": \"Ivano-Frankivska oblast\",\n \"UA-63\": \"Kharkivska oblast\",\n \"UA-65\": \"Khersonska oblast\",\n \"UA-68\": \"Khmelnytska oblast\",\n \"UA-35\": \"Kirovohradska oblast\",\n \"UA-30\": \"Kyiv\",\n \"UA-32\": \"Kyivska oblast\",\n \"UA-09\": \"Luhanska oblast\",\n \"UA-46\": \"Lvivska oblast\",\n \"UA-48\": \"Mykolaivska oblast\",\n \"UA-51\": \"Odeska oblast\",\n \"UA-53\": \"Poltavska oblast\",\n \"UA-56\": \"Rivnenska oblast\",\n \"UA-40\": \"Sevastopol\",\n \"UA-59\": \"Sumska oblast\",\n \"UA-61\": \"Ternopilska oblast\",\n \"UA-05\": \"Vinnytska oblast\",\n \"UA-07\": \"Volynska oblast\",\n \"UA-21\": \"Zakarpatska oblast\",\n \"UA-23\": \"Zaporizka oblast\",\n \"UA-18\": \"Zhytomyrska oblast\",\n \"AE-AJ\": \"‘Ajmān\",\n \"AE-AZ\": \"Abū Z̧aby\",\n \"AE-FU\": \"Al Fujayrah\",\n \"AE-SH\": \"Ash Shāriqah\",\n \"AE-DU\": \"Dubayy\",\n \"AE-RK\": \"Ra’s al Khaymah\",\n \"AE-UQ\": \"Umm al Qaywayn\",\n \"GB-ENG\": \"England\",\n \"GB-NIR\": \"Northern Ireland\",\n \"GB-SCT\": \"Scotland\",\n \"GB-WLS\": \"Wales\",\n \"US-AL\": \"Alabama\",\n \"US-AK\": \"Alaska\",\n \"US-AZ\": \"Arizona\",\n \"US-AR\": \"Arkansas\",\n \"US-CA\": \"California\",\n \"US-CO\": \"Colorado\",\n \"US-CT\": \"Connecticut\",\n \"US-DE\": \"Delaware\",\n \"US-FL\": \"Florida\",\n \"US-GA\": \"Georgia\",\n \"US-HI\": \"Hawaii\",\n \"US-ID\": \"Idaho\",\n \"US-IL\": \"Illinois\",\n \"US-IN\": \"Indiana\",\n \"US-IA\": \"Iowa\",\n \"US-KS\": \"Kansas\",\n \"US-KY\": \"Kentucky\",\n \"US-LA\": \"Louisiana\",\n \"US-ME\": \"Maine\",\n \"US-MD\": \"Maryland\",\n \"US-MA\": \"Massachusetts\",\n \"US-MI\": \"Michigan\",\n \"US-MN\": \"Minnesota\",\n \"US-MS\": \"Mississippi\",\n \"US-MO\": \"Missouri\",\n \"US-MT\": \"Montana\",\n \"US-NE\": \"Nebraska\",\n \"US-NV\": \"Nevada\",\n \"US-NH\": \"New Hampshire\",\n \"US-NJ\": \"New Jersey\",\n \"US-NM\": \"New Mexico\",\n \"US-NY\": \"New York\",\n \"US-NC\": \"North Carolina\",\n \"US-ND\": \"North Dakota\",\n \"US-OH\": \"Ohio\",\n \"US-OK\": \"Oklahoma\",\n \"US-OR\": \"Oregon\",\n \"US-PA\": \"Pennsylvania\",\n \"US-RI\": \"Rhode Island\",\n \"US-SC\": \"South Carolina\",\n \"US-SD\": \"South Dakota\",\n \"US-TN\": \"Tennessee\",\n \"US-TX\": \"Texas\",\n \"US-UT\": \"Utah\",\n \"US-VT\": \"Vermont\",\n \"US-VA\": \"Virginia\",\n \"US-WA\": \"Washington\",\n \"US-WV\": \"West Virginia\",\n \"US-WI\": \"Wisconsin\",\n \"US-WY\": \"Wyoming\",\n \"US-DC\": \"District of Columbia\",\n \"US-AS\": \"American Samoa\",\n \"US-GU\": \"Guam\",\n \"US-MP\": \"Northern Mariana Islands\",\n \"US-PR\": \"Puerto Rico\",\n \"US-UM\": \"United States Minor Outlying Islands\",\n \"US-VI\": \"Virgin Islands\",\n \"UM-81\": \"Baker Island\",\n \"UM-84\": \"Howland Island\",\n \"UM-86\": \"Jarvis Island\",\n \"UM-67\": \"Johnston Atoll\",\n \"UM-89\": \"Kingman Reef\",\n \"UM-71\": \"Midway Islands\",\n \"UM-76\": \"Navassa Island\",\n \"UM-95\": \"Palmyra Atoll\",\n \"UM-79\": \"Wake Island\",\n \"UY-AR\": \"Artigas\",\n \"UY-CA\": \"Canelones\",\n \"UY-CL\": \"Cerro Largo\",\n \"UY-CO\": \"Colonia\",\n \"UY-DU\": \"Durazno\",\n \"UY-FS\": \"Flores\",\n \"UY-FD\": \"Florida\",\n \"UY-LA\": \"Lavalleja\",\n \"UY-MA\": \"Maldonado\",\n \"UY-MO\": \"Montevideo\",\n \"UY-PA\": \"Paysandú\",\n \"UY-RN\": \"Río Negro\",\n \"UY-RV\": \"Rivera\",\n \"UY-RO\": \"Rocha\",\n \"UY-SA\": \"Salto\",\n \"UY-SJ\": \"San José\",\n \"UY-SO\": \"Soriano\",\n \"UY-TA\": \"Tacuarembó\",\n \"UY-TT\": \"Treinta y Tres\",\n \"UZ-AN\": \"Andijon\",\n \"UZ-BU\": \"Buxoro\",\n \"UZ-FA\": \"Farg‘ona\",\n \"UZ-JI\": \"Jizzax\",\n \"UZ-NG\": \"Namangan\",\n \"UZ-NW\": \"Navoiy\",\n \"UZ-QA\": \"Qashqadaryo\",\n \"UZ-QR\": \"Qoraqalpog‘iston Respublikasi\",\n \"UZ-SA\": \"Samarqand\",\n \"UZ-SI\": \"Sirdaryo\",\n \"UZ-SU\": \"Surxondaryo\",\n \"UZ-TK\": \"Toshkent\",\n \"UZ-TO\": \"Toshkent\",\n \"UZ-XO\": \"Xorazm\",\n \"VU-MAP\": \"Malampa\",\n \"VU-PAM\": \"Pénama\",\n \"VU-SAM\": \"Sanma\",\n \"VU-SEE\": \"Shéfa\",\n \"VU-TAE\": \"Taféa\",\n \"VU-TOB\": \"Torba\",\n \"VE-Z\": \"Amazonas\",\n \"VE-B\": \"Anzoátegui\",\n \"VE-C\": \"Apure\",\n \"VE-D\": \"Aragua\",\n \"VE-E\": \"Barinas\",\n \"VE-F\": \"Bolívar\",\n \"VE-G\": \"Carabobo\",\n \"VE-H\": \"Cojedes\",\n \"VE-Y\": \"Delta Amacuro\",\n \"VE-W\": \"Dependencias Federales\",\n \"VE-A\": \"Distrito Capital\",\n \"VE-I\": \"Falcón\",\n \"VE-J\": \"Guárico\",\n \"VE-X\": \"La Guaira\",\n \"VE-K\": \"Lara\",\n \"VE-L\": \"Mérida\",\n \"VE-M\": \"Miranda\",\n \"VE-N\": \"Monagas\",\n \"VE-O\": \"Nueva Esparta\",\n \"VE-P\": \"Portuguesa\",\n \"VE-R\": \"Sucre\",\n \"VE-S\": \"Táchira\",\n \"VE-T\": \"Trujillo\",\n \"VE-U\": \"Yaracuy\",\n \"VE-V\": \"Zulia\",\n \"VN-44\": \"An Giang\",\n \"VN-43\": \"Bà Rịa - Vũng Tàu\",\n \"VN-54\": \"Bắc Giang\",\n \"VN-53\": \"Bắc Kạn\",\n \"VN-55\": \"Bạc Liêu\",\n \"VN-56\": \"Bắc Ninh\",\n \"VN-50\": \"Bến Tre\",\n \"VN-31\": \"Bình Định\",\n \"VN-57\": \"Bình Dương\",\n \"VN-58\": \"Bình Phước\",\n \"VN-40\": \"Bình Thuận\",\n \"VN-59\": \"Cà Mau\",\n \"VN-CT\": \"Cần Thơ\",\n \"VN-04\": \"Cao Bằng\",\n \"VN-DN\": \"Đà Nẵng\",\n \"VN-33\": \"Đắk Lắk\",\n \"VN-72\": \"Đắk Nông\",\n \"VN-71\": \"Điện Biên\",\n \"VN-39\": \"Đồng Nai\",\n \"VN-45\": \"Đồng Tháp\",\n \"VN-30\": \"Gia Lai\",\n \"VN-03\": \"Hà Giang\",\n \"VN-63\": \"Hà Nam\",\n \"VN-HN\": \"Hà Nội\",\n \"VN-23\": \"Hà Tĩnh\",\n \"VN-61\": \"Hải Dương\",\n \"VN-HP\": \"Hải Phòng\",\n \"VN-73\": \"Hậu Giang\",\n \"VN-SG\": \"Hồ Chí Minh\",\n \"VN-14\": \"Hòa Bình\",\n \"VN-66\": \"Hưng Yên\",\n \"VN-34\": \"Khánh Hòa\",\n \"VN-47\": \"Kiến Giang\",\n \"VN-28\": \"Kon Tum\",\n \"VN-01\": \"Lai Châu\",\n \"VN-35\": \"Lâm Đồng\",\n \"VN-09\": \"Lạng Sơn\",\n \"VN-02\": \"Lào Cai\",\n \"VN-41\": \"Long An\",\n \"VN-67\": \"Nam Định\",\n \"VN-22\": \"Nghệ An\",\n \"VN-18\": \"Ninh Bình\",\n \"VN-36\": \"Ninh Thuận\",\n \"VN-68\": \"Phú Thọ\",\n \"VN-32\": \"Phú Yên\",\n \"VN-24\": \"Quảng Bình\",\n \"VN-27\": \"Quảng Nam\",\n \"VN-29\": \"Quảng Ngãi\",\n \"VN-13\": \"Quảng Ninh\",\n \"VN-25\": \"Quảng Trị\",\n \"VN-52\": \"Sóc Trăng\",\n \"VN-05\": \"Sơn La\",\n \"VN-37\": \"Tây Ninh\",\n \"VN-20\": \"Thái Bình\",\n \"VN-69\": \"Thái Nguyên\",\n \"VN-21\": \"Thanh Hóa\",\n \"VN-26\": \"Thừa Thiên-Huế\",\n \"VN-46\": \"Tiền Giang\",\n \"VN-51\": \"Trà Vinh\",\n \"VN-07\": \"Tuyên Quang\",\n \"VN-49\": \"Vĩnh Long\",\n \"VN-70\": \"Vĩnh Phúc\",\n \"VN-06\": \"Yên Bái\",\n \"WF-AL\": \"Alo\",\n \"WF-SG\": \"Sigave\",\n \"WF-UV\": \"Uvea\",\n \"YE-AD\": \"‘Adan\",\n \"YE-AM\": \"‘Amrān\",\n \"YE-AB\": \"Abyan\",\n \"YE-DA\": \"Aḑ Ḑāli‘\",\n \"YE-BA\": \"Al Bayḑā’\",\n \"YE-HU\": \"Al Ḩudaydah\",\n \"YE-JA\": \"Al Jawf\",\n \"YE-MR\": \"Al Mahrah\",\n \"YE-MW\": \"Al Maḩwīt\",\n \"YE-SA\": \"Amānat al ‘Āşimah\",\n \"YE-SU\": \"Arkhabīl Suquţrá\",\n \"YE-DH\": \"Dhamār\",\n \"YE-HD\": \"Ḩaḑramawt\",\n \"YE-HJ\": \"Ḩajjah\",\n \"YE-IB\": \"Ibb\",\n \"YE-LA\": \"Laḩij\",\n \"YE-MA\": \"Ma’rib\",\n \"YE-RA\": \"Raymah\",\n \"YE-SD\": \"Şāʻdah\",\n \"YE-SN\": \"Şanʻā’\",\n \"YE-SH\": \"Shabwah\",\n \"YE-TA\": \"Tāʻizz\",\n \"ZM-02\": \"Central\",\n \"ZM-08\": \"Copperbelt\",\n \"ZM-03\": \"Eastern\",\n \"ZM-04\": \"Luapula\",\n \"ZM-09\": \"Lusaka\",\n \"ZM-10\": \"Muchinga\",\n \"ZM-06\": \"North-Western\",\n \"ZM-05\": \"Northern\",\n \"ZM-07\": \"Southern\",\n \"ZM-01\": \"Western\",\n \"ZW-BU\": \"Bulawayo\",\n \"ZW-HA\": \"Harare\",\n \"ZW-MA\": \"Manicaland\",\n \"ZW-MC\": \"Mashonaland Central\",\n \"ZW-ME\": \"Mashonaland East\",\n \"ZW-MW\": \"Mashonaland West\",\n \"ZW-MV\": \"Masvingo\",\n \"ZW-MN\": \"Matabeleland North\",\n \"ZW-MS\": \"Matabeleland South\",\n \"ZW-MI\": \"Midlands\",\n \"BQ-BO\": \"Bonaire\",\n \"BQ-SA\": \"Saba\",\n \"BQ-SE\": \"Sint Eustatius\",\n \"ME-01\": \"Andrijevica\",\n \"ME-02\": \"Bar\",\n \"ME-03\": \"Berane\",\n \"ME-04\": \"Bijelo Polje\",\n \"ME-05\": \"Budva\",\n \"ME-06\": \"Cetinje\",\n \"ME-07\": \"Danilovgrad\",\n \"ME-22\": \"Gusinje\",\n \"ME-08\": \"Herceg-Novi\",\n \"ME-09\": \"Kolašin\",\n \"ME-10\": \"Kotor\",\n \"ME-11\": \"Mojkovac\",\n \"ME-12\": \"Nikšić\",\n \"ME-23\": \"Petnjica\",\n \"ME-13\": \"Plav\",\n \"ME-14\": \"Pljevlja\",\n \"ME-15\": \"Plužine\",\n \"ME-16\": \"Podgorica\",\n \"ME-17\": \"Rožaje\",\n \"ME-18\": \"Šavnik\",\n \"ME-19\": \"Tivat\",\n \"ME-24\": \"Tuzi\",\n \"ME-20\": \"Ulcinj\",\n \"ME-21\": \"Žabljak\",\n \"ME-25\": \"Zeta\",\n \"RS-KM\": \"Kosovo-Metohija\",\n \"RS-VO\": \"Vojvodina\",\n \"SS-EC\": \"Central Equatoria\",\n \"SS-EE\": \"Eastern Equatoria\",\n \"SS-JG\": \"Jonglei\",\n \"SS-LK\": \"Lakes\",\n \"SS-BN\": \"Northern Bahr el Ghazal\",\n \"SS-UY\": \"Unity\",\n \"SS-NU\": \"Upper Nile\",\n \"SS-WR\": \"Warrap\",\n \"SS-BW\": \"Western Bahr el Ghazal\",\n \"SS-EW\": \"Western Equatoria\",\n};\n\nexport const REGION_CODES = Object.keys(REGIONS) as [string, ...string[]];\n","/**\n * Country Code Top-Level Domains (ccTLDs)\n * Provides a comprehensive set of all country-specific domain extensions\n */\n\n/**\n * A Set containing ISO 3166-1 alpha-2 country code top-level domains (ccTLDs),\n * plus a small set of commonly-recognized regional TLDs (`eu`, `eus`, `gal`,\n * `cat`, `asia`). De-duplicated and pruned of retired/withdrawn codes:\n * - `an` (Netherlands Antilles, retired 2010)\n * - `tp` (Timor-Leste, retired 2015 — use `tl`)\n * `gb` is included alongside `uk` per IANA reservation.\n *\n * @example\n * ```ts\n * import { ccTLDs } from '@kumix/utils';\n *\n * // Check if a TLD is a country code TLD\n * const isCountryTLD = ccTLDs.has('uk'); // true\n *\n * // Extract TLD from domain and check\n * const domain = 'example.co.uk';\n * const tld = domain.split('.').pop();\n * const isCountryDomain = tld ? ccTLDs.has(tld) : false; // true\n * ```\n */\nexport const ccTLDs = new Set([\n \"ac\",\n \"ad\",\n \"ae\",\n \"af\",\n \"ag\",\n \"ai\",\n \"al\",\n \"am\",\n \"ao\",\n \"aq\",\n \"ar\",\n \"as\",\n \"at\",\n \"au\",\n \"aw\",\n \"ax\",\n \"az\",\n \"ba\",\n \"bb\",\n \"bd\",\n \"be\",\n \"bf\",\n \"bg\",\n \"bh\",\n \"bi\",\n \"bj\",\n \"bl\",\n \"bm\",\n \"bn\",\n \"bo\",\n \"bq\",\n \"br\",\n \"bs\",\n \"bt\",\n \"bv\",\n \"bw\",\n \"by\",\n \"bz\",\n \"ca\",\n \"cat\",\n \"cc\",\n \"cd\",\n \"cf\",\n \"cg\",\n \"ch\",\n \"ci\",\n \"ck\",\n \"cl\",\n \"cm\",\n \"cn\",\n \"co\",\n \"cr\",\n \"cu\",\n \"cv\",\n \"cw\",\n \"cx\",\n \"cy\",\n \"cz\",\n \"de\",\n \"dj\",\n \"dk\",\n \"dm\",\n \"do\",\n \"dz\",\n \"ec\",\n \"ee\",\n \"eg\",\n \"eh\",\n \"er\",\n \"es\",\n \"et\",\n \"eu\",\n \"eus\",\n \"fi\",\n \"fj\",\n \"fk\",\n \"fm\",\n \"fo\",\n \"fr\",\n \"ga\",\n \"gal\",\n \"gb\",\n \"gd\",\n \"ge\",\n \"gf\",\n \"gg\",\n \"gh\",\n \"gi\",\n \"gl\",\n \"gm\",\n \"gn\",\n \"gp\",\n \"gq\",\n \"gr\",\n \"gs\",\n \"gt\",\n \"gu\",\n \"gw\",\n \"gy\",\n \"hk\",\n \"hm\",\n \"hn\",\n \"hr\",\n \"ht\",\n \"hu\",\n \"id\",\n \"ie\",\n \"il\",\n \"im\",\n \"in\",\n \"io\",\n \"iq\",\n \"ir\",\n \"is\",\n \"it\",\n \"je\",\n \"jm\",\n \"jo\",\n \"jp\",\n \"ke\",\n \"kg\",\n \"kh\",\n \"ki\",\n \"km\",\n \"kn\",\n \"kp\",\n \"kr\",\n \"kw\",\n \"ky\",\n \"kz\",\n \"la\",\n \"lb\",\n \"lc\",\n \"li\",\n \"lk\",\n \"lr\",\n \"ls\",\n \"lt\",\n \"lu\",\n \"lv\",\n \"ly\",\n \"ma\",\n \"mc\",\n \"md\",\n \"me\",\n \"mf\",\n \"mg\",\n \"mh\",\n \"mk\",\n \"ml\",\n \"mm\",\n \"mn\",\n \"mo\",\n \"mp\",\n \"mq\",\n \"mr\",\n \"ms\",\n \"mt\",\n \"mu\",\n \"mv\",\n \"mw\",\n \"mx\",\n \"my\",\n \"mz\",\n \"na\",\n \"nc\",\n \"ne\",\n \"nf\",\n \"ng\",\n \"ni\",\n \"nl\",\n \"no\",\n \"np\",\n \"nr\",\n \"nu\",\n \"nz\",\n \"om\",\n \"pa\",\n \"pe\",\n \"pf\",\n \"pg\",\n \"ph\",\n \"pk\",\n \"pl\",\n \"pm\",\n \"pn\",\n \"pr\",\n \"ps\",\n \"pt\",\n \"pw\",\n \"py\",\n \"qa\",\n \"re\",\n \"ro\",\n \"rs\",\n \"ru\",\n \"rw\",\n \"sa\",\n \"sb\",\n \"sc\",\n \"sd\",\n \"se\",\n \"sg\",\n \"sh\",\n \"si\",\n \"sj\",\n \"sk\",\n \"sl\",\n \"sm\",\n \"sn\",\n \"so\",\n \"sr\",\n \"ss\",\n \"st\",\n \"sv\",\n \"sx\",\n \"sy\",\n \"sz\",\n \"tc\",\n \"td\",\n \"tf\",\n \"tg\",\n \"th\",\n \"tj\",\n \"tk\",\n \"tl\",\n \"tm\",\n \"tn\",\n \"to\",\n \"tr\",\n \"tt\",\n \"tv\",\n \"tw\",\n \"tz\",\n \"ua\",\n \"ug\",\n \"uk\",\n \"um\",\n \"us\",\n \"uy\",\n \"uz\",\n \"va\",\n \"vc\",\n \"ve\",\n \"vg\",\n \"vi\",\n \"vn\",\n \"vu\",\n \"wf\",\n \"ws\",\n \"ye\",\n \"za\",\n \"zm\",\n \"zw\",\n]);\n","/**\n * Domain Constants\n * Provides sets of domain-related constants for URL parsing and validation\n */\n\n/**\n * Common second-level domains used in domain name structures\n * Used for domain parsing, validation, and extraction of root domains\n *\n * @example\n * ```ts\n * import { SECOND_LEVEL_DOMAINS } from '@kumix/utils';\n *\n * // Check if a domain part is a common second-level domain\n * const isSecondLevelDomain = SECOND_LEVEL_DOMAINS.has('co'); // true\n *\n * // Extract root domain from a URL\n * function getRootDomain(url: string) {\n * const hostname = new URL(url).hostname;\n * const parts = hostname.split('.');\n *\n * // Handle cases like example.co.uk\n * if (parts.length > 2 && SECOND_LEVEL_DOMAINS.has(parts[parts.length - 2])) {\n * return parts.slice(-3).join('.');\n * }\n *\n * // Handle normal cases like example.com\n * return parts.slice(-2).join('.');\n * }\n * ```\n */\nexport const SECOND_LEVEL_DOMAINS = new Set([\"com\", \"co\", \"net\", \"org\", \"edu\", \"gov\", \"in\"]);\n","/**\n * Domain Constants\n * Provides sets of domain-related constants for URL parsing and validation\n */\n\n/**\n * Special apex domains that require special handling\n * These domains are typically used for hosting services where users get subdomains\n *\n * @example\n * ```ts\n * import { SPECIAL_APEX_DOMAINS } from '@kumix/utils';\n *\n * // Check if a domain is a special hosting domain\n * const isSpecialDomain = SPECIAL_APEX_DOMAINS.has('vercel.app'); // true\n *\n * // Determine if a hostname is a user subdomain on a special apex domain\n * function isUserSubdomain(hostname: string) {\n * const parts = hostname.split('.');\n * if (parts.length < 2) return false;\n *\n * const possibleApexDomain = parts.slice(-2).join('.');\n * return SPECIAL_APEX_DOMAINS.has(possibleApexDomain);\n * }\n *\n * // Extract username from special domains\n * function extractUsername(hostname: string) {\n * const parts = hostname.split('.');\n * const possibleApexDomain = parts.slice(-2).join('.');\n *\n * if (SPECIAL_APEX_DOMAINS.has(possibleApexDomain)) {\n * return parts.slice(0, -2).join('.');\n * }\n * return null;\n * }\n * ```\n */\nexport const SPECIAL_APEX_DOMAINS = new Set([\n \"my.id\",\n \"github.io\",\n \"vercel.app\",\n \"now.sh\",\n \"pages.dev\",\n \"webflow.io\",\n \"netlify.app\",\n \"fly.dev\",\n \"web.app\",\n]);\n","/**\n * Theme configuration for the application\n * Handles light, dark, and system theme modes with their respective colors\n */\n\n/**\n * Available theme modes in the application\n * - light: Force light theme\n * - dark: Force dark theme\n * - system: Follow system/OS preference (auto-detect)\n */\nexport const THEME_MODES = {\n LIGHT: \"light\",\n DARK: \"dark\",\n SYSTEM: \"system\",\n} as const;\n\n/**\n * Type definition for theme modes\n */\nexport type ThemeMode = (typeof THEME_MODES)[keyof typeof THEME_MODES];\n\n/**\n * Meta theme colors for different theme modes\n * Used for:\n * - HTML meta theme-color tags\n * - Browser address bar coloring\n * - PWA theme colors\n * - System theme integration\n */\nexport const META_THEME_COLORS = {\n /** Light theme color - Pure white for clean, bright appearance */\n [THEME_MODES.LIGHT]: \"#ffffff\",\n /** Dark theme color - Near black with slight warmth to reduce eye strain */\n [THEME_MODES.DARK]: \"#09090b\",\n /** System theme - Will be determined by user's OS preference */\n [THEME_MODES.SYSTEM]: \"auto\", // Special value indicating system preference\n} as const;\n\n/**\n * Default theme mode when no preference is set\n * Falls back to system preference to respect user's OS settings\n */\nexport const DEFAULT_THEME_MODE: ThemeMode = THEME_MODES.SYSTEM;\n","/**\n * Environment variables used throughout the application\n * Centralizes all environment variable access for easier management and documentation.\n */\n\nimport { getEnv } from \"../env\";\n\n/**\n * Recaptcha site key for client-side verification.\n * Used for Google reCAPTCHA integration in forms and authentication.\n *\n * @example\n * <Recaptcha siteKey={NEXT_PUBLIC_RECAPTCHA_SITE_KEY} />\n */\nexport const NEXT_PUBLIC_RECAPTCHA_SITE_KEY = getEnv(\"NEXT_PUBLIC_RECAPTCHA_SITE_KEY\");\n\n/**\n * Recaptcha secret key for server-side token verification.\n * Used by verifyRecaptchaToken to call Google's siteverify endpoint.\n * Must NOT be exposed to the client (no NEXT_PUBLIC prefix).\n *\n * @example\n * const isValid = await verifyRecaptchaToken(token);\n */\nexport const RECAPTCHA_SECRET_KEY = getEnv(\"RECAPTCHA_SECRET_KEY\");\n\n/**\n * Slack webhook URLs for different log types.\n * Used for sending log messages to specific Slack channels based on log category.\n *\n * @property {string | undefined} ALERTS - Webhook for alert notifications\n * @property {string | undefined} CRON - Webhook for cron job logs\n * @property {string | undefined} LINKS - Webhook for link-related logs\n * @property {string | undefined} SUBSCRIBERS - Webhook for subscriber events\n * @property {string | undefined} ERRORS - Webhook for error logs\n *\n * @example\n * fetch(SLACK_WEBHOOKS.ALERTS, { method: 'POST', body: ... })\n */\nexport const SLACK_WEBHOOKS = {\n ALERTS: getEnv(\"SLACK_WEBHOOKS_HOOK_ALERTS\"),\n CRON: getEnv(\"SLACK_WEBHOOKS_HOOK_CRON\"),\n LINKS: getEnv(\"SLACK_WEBHOOKS_HOOK_LINKS\"),\n SUBSCRIBERS: getEnv(\"SLACK_WEBHOOKS_HOOK_SUBSCRIBERS\"),\n ERRORS: getEnv(\"SLACK_WEBHOOKS_HOOK_ERRORS\"),\n};\n\n/**\n * Default URL for Open Graph avatar images.\n * Used for generating user or entity avatars in OG images.\n *\n * @example\n * <img src={OG_AVATAR_URL + userId} />\n */\nexport const OG_AVATAR_URL = \"https://api.kumix.io/og/avatar/\";\n\n/**\n * Default pagination limit for API responses and UI lists.\n *\n * @example\n * const items = data.slice(0, PAGINATION_LIMIT);\n */\nexport const PAGINATION_LIMIT = 100;\n\n/**\n * Number of seconds in two weeks.\n * Useful for cookie expiration, session timeouts, etc.\n *\n * @example\n * cookie.set('token', value, { maxAge: TWO_WEEKS_IN_SECONDS });\n */\nexport const TWO_WEEKS_IN_SECONDS = 60 * 60 * 24 * 14;\n\n/**\n * The beginning of time for the application (arbitrary early date).\n * Used as a default value for date comparisons or migrations.\n *\n * @example\n * if (createdAt < THE_BEGINNING_OF_TIME) { ... }\n */\nexport const THE_BEGINNING_OF_TIME = new Date(\"2010-01-01T00:00:00.000Z\");\n\n/**\n * A large number used as a practical infinity in calculations.\n *\n * @example\n * if (count > INFINITY_NUMBER) { ... }\n */\nexport const INFINITY_NUMBER = 1000000000;\n\n/**\n * Query parameter name for redirection URLs.\n * Used to pass redirect destinations in authentication or navigation flows.\n *\n * @example\n * const url = `/login?${REDIRECTION_QUERY_PARAM}=/dashboard`;\n */\nexport const REDIRECT_QUERY_PARAM = \"redirectTo\";\n\n/**\n * LocalStorage key for storing the last visited workspace.\n * Used to persist user's last active workspace between sessions.\n */\nexport const LAST_VISITED_WORKSPACE = \"last-visited-workspace\";\n","/**\n * Constants for Framer Motion animations\n * Provides reusable animation presets for consistent UI motion\n */\n\n/**\n * Animation variants for list items\n * Creates a scale and fade effect for list items\n *\n * @example\n * ```tsx\n * import { motion } from 'framer-motion';\n * import { FRAMER_MOTION_LIST_ITEM_VARIANTS } from '@kumix/utils';\n *\n * // In a component\n * <motion.li\n * variants={FRAMER_MOTION_LIST_ITEM_VARIANTS}\n * initial=\"hidden\"\n * animate=\"show\"\n * >\n * List item content\n * </motion.li>\n * ```\n */\nexport const FRAMER_MOTION_LIST_ITEM_VARIANTS = {\n hidden: { scale: 0.8, opacity: 0 },\n show: { scale: 1, opacity: 1, transition: { type: \"spring\" } },\n};\n\n/**\n * Animation variants for staggered children elements\n * Creates a fade-in and slide-up effect with spring physics\n *\n * @example\n * ```tsx\n * import { motion } from 'framer-motion';\n * import { STAGGER_CHILD_VARIANTS } from '@kumix/utils';\n *\n * // In a parent component\n * <motion.ul\n * initial=\"hidden\"\n * animate=\"show\"\n * variants={{\n * show: {\n * transition: {\n * staggerChildren: 0.1\n * }\n * }\n * }}\n * >\n * {items.map(item => (\n * <motion.li key={item.id} variants={STAGGER_CHILD_VARIANTS}>\n * {item.content}\n * </motion.li>\n * ))}\n * </motion.ul>\n * ```\n */\nexport const STAGGER_CHILD_VARIANTS = {\n hidden: { opacity: 0, y: 20 },\n show: { opacity: 1, y: 0, transition: { duration: 0.4, type: \"spring\" } },\n};\n\n/**\n * Animation settings for tab items\n * Creates a smooth transition effect for tab switching\n *\n * @example\n * ```tsx\n * import { motion, AnimatePresence } from 'framer-motion';\n * import { TAB_ITEM_ANIMATION_SETTINGS } from '@kumix/utils';\n *\n * // In a component\n * <AnimatePresence mode=\"wait\">\n * <motion.div\n * key={activeTab}\n * {...TAB_ITEM_ANIMATION_SETTINGS}\n * >\n * {tabContent}\n * </motion.div>\n * </AnimatePresence>\n * ```\n */\nexport const TAB_ITEM_ANIMATION_SETTINGS = {\n initial: { opacity: 0, y: -10 },\n animate: { opacity: 1, y: 0 },\n exit: { opacity: 0, y: -10 },\n transition: { duration: 0.2, type: \"easeInOut\" },\n};\n","/**\n * Localhost Constants\n * Provides default geolocation and IP data for local development environments\n */\n\n/**\n * Default geolocation data for localhost/development environments\n * Used when actual geolocation data is unavailable or for testing location-based features\n *\n * @example\n * ```ts\n * import { LOCALHOST_GEO_DATA } from '@kumix/utils';\n *\n * // Use default geo data when in development environment\n * const geoData = isDevelopment ? LOCALHOST_GEO_DATA : userGeoData;\n *\n * // Testing location-based features\n * function getNearbyStores(userLocation = LOCALHOST_GEO_DATA) {\n * const { latitude, longitude } = userLocation;\n * // Implementation to find nearby stores\n * }\n * ```\n */\nexport const LOCALHOST_GEO_DATA = {\n continent: \"NA\",\n country: \"US\",\n city: \"San Francisco\",\n region: \"CA\",\n latitude: \"37.7695\",\n longitude: \"-122.385\",\n};\n\n/**\n * Default IP address for localhost/development environments\n * Used when actual IP data is unavailable or for testing IP-based features\n *\n * @example\n * ```ts\n * import { LOCALHOST_IP } from '@kumix/utils';\n *\n * // Use default IP when in development environment\n * const ipAddress = isDevelopment ? LOCALHOST_IP : userIpAddress;\n *\n * // Testing IP-based features\n * function getLocationFromIp(ip = LOCALHOST_IP) {\n * // Implementation to get location from IP\n * }\n * ```\n */\n// Use an RFC5737 TEST-NET address so dev/test IP lookups never hit a real\n// third-party service (the previous value 63.141.57.109 is a routable public\n// IP). TEST-NET 2 (198.51.100.0/24) is reserved for documentation/examples.\nexport const LOCALHOST_IP = \"198.51.100.1\";\n","/**\n * Reserved Slugs Constants\n * Provides a list of reserved slugs that cannot be used for user-generated content\n */\n\n/**\n * Array of reserved slugs that cannot be used as workspace slugs or custom paths\n * These are reserved for system use, existing routes, or to prevent confusion/abuse\n *\n * @example\n * ```ts\n * import { RESERVED_SLUGS } from '@kumix/utils';\n *\n * // Check if a slug is reserved\n * function isSlugReserved(slug: string) {\n * return RESERVED_SLUGS.includes(slug.toLowerCase());\n * }\n *\n * // Validate user input for custom workspace slug\n * function validateWorkspaceSlug(slug: string) {\n * if (RESERVED_SLUGS.includes(slug.toLowerCase())) {\n * return {\n * valid: false,\n * error: 'This slug is reserved. Please choose another one.'\n * };\n * }\n * return { valid: true };\n * }\n *\n * // Generate a unique slug that's not reserved\n * function generateUniqueSlug(baseName: string) {\n * let slug = baseName.toLowerCase().replace(/\\s+/g, '-');\n *\n * if (RESERVED_SLUGS.includes(slug)) {\n * // Append a random string or number if the slug is reserved\n * slug = `${slug}-${Math.random().toString(36).substring(2, 7)}`;\n * }\n *\n * return slug;\n * }\n * ```\n */\nexport const RESERVED_SLUGS = [\n /** 🔒 Platform reserved (root-level, system critical) */\n \"va\",\n \"static\",\n \"proxy\",\n \"robots\",\n \"robots.txt\",\n \"_next\",\n \"favicon\",\n \"sitemap\",\n \"error\",\n \"home\",\n \"app\",\n \"www\",\n\n /** 🧩 Marketing / public pages */\n \"about\",\n \"blog\",\n \"changelog\",\n \"careers\",\n \"contact\",\n \"demo\",\n \"docs\",\n \"features\",\n \"guides\",\n \"help\",\n \"info\",\n \"pricing\",\n \"privacy\",\n \"resources\",\n \"terms\",\n\n /** 🧭 Navigation / procedural flow */\n \"new\",\n \"invite\",\n \"invitation\",\n \"join\",\n \"accept\",\n \"verify\",\n \"onboarding\",\n\n /** 🌐 Social / external integrations */\n \"discord\",\n \"reddit\",\n\n /** 🧑‍💼 Auth routes */\n \"auth\",\n \"signin\",\n \"signout\",\n \"signup\",\n \"forgot-password\",\n \"reset-password\",\n \"recover-account\",\n \"magic-link\",\n \"email-otp\",\n \"two-factor\",\n \"2fa\",\n\n /** 🏢 Workspace / organization / user */\n \"account\",\n \"accounts\",\n \"billing\",\n \"billings\",\n \"organization\",\n \"organizations\",\n \"workspace\",\n \"workspaces\",\n \"setting\",\n \"settings\",\n \"domains\",\n\n /** 👥 Members / people */\n \"member\",\n \"members\",\n \"people\",\n \"peoples\",\n \"user\",\n \"users\",\n\n /** 🛠 API & integrations */\n \"api\",\n \"webhooks\",\n \"analytics\",\n \"metatags\",\n\n /** 📈 Business / revenue features */\n \"campaigns\",\n \"links\",\n \"events\",\n \"referrals\",\n \"upgrade\",\n \"wrapped\",\n \"invoices\",\n \"programs\",\n \"partners\",\n \"payouts\",\n \"commissions\",\n \"sales\",\n\n /** ⚙️ Admin / dashboard */\n \"admin\",\n \"dashboard\",\n];\n","/**\n * Google Analytics tracking utilities for React applications\n * Provides comprehensive event tracking with validation and error handling\n * Supports GA4 event structure and CRUD operations tracking\n *\n * DIFFERENCE FROM HOOKS/USE-ANALYTICS:\n * - This lib provides standalone utility functions for direct event tracking\n * - use-analytics hook provides React-specific state management and lifecycle integration\n * - This lib is for simple, direct GA tracking without React context\n * - use-analytics hook is for complex SaaS module tracking with React integration\n *\n * USE CASES:\n * - Use this lib for: Simple event tracking, non-React contexts, utility functions\n * - Use hooks for: Complex SaaS tracking, React components, state-dependent tracking\n */\n\nimport { logger } from \"../logging/logger\";\n\n/**\n * Interface for event tracking parameters\n * Defines the structure for tracking events in Google Analytics\n */\ninterface EventProps {\n /** Event name to be tracked (required, non-empty string) */\n name: string;\n /** Optional properties/attributes for the event */\n properties?: Record<string, string | number | boolean>;\n}\n\n/**\n * Global declaration for Google Analytics gtag function\n * This extends the Window interface to include the gtag function\n * that's injected by the Google Analytics script\n */\ndeclare global {\n interface Window {\n gtag?: (\n command: \"event\" | \"config\" | \"set\",\n targetId: string,\n config?: Record<string, string | number | boolean | object | null | undefined>,\n ) => void;\n }\n}\n\n/**\n * Tracks an event in Google Analytics with proper error handling and validation.\n *\n * @param params - Event parameters\n * @param params.name - Event name (required, non-empty string)\n * @param params.properties - Optional event properties\n */\nexport const googleTrackEvent = ({ name, properties }: EventProps) => {\n // Validate required parameters\n if (!name || typeof name !== \"string\" || name.trim().length === 0) {\n logger.warn(\"Analytics: Event name is required and must be a non-empty string\");\n return;\n }\n\n // Validate properties if provided\n if (properties && typeof properties !== \"object\") {\n logger.warn(\"Analytics: Properties must be an object\");\n return;\n }\n\n try {\n // Track in Google Analytics\n if (typeof window !== \"undefined\" && window.gtag) {\n // GA4 recommended event structure\n window.gtag(\"event\", name.trim(), {\n ...properties,\n // GA4 recommended parameters\n event_category: properties?.category || \"engagement\",\n event_label: properties?.label,\n value: properties?.value,\n });\n }\n } catch (error) {\n logger.error(\"Analytics: Failed to track event\", { name, error });\n }\n};\n\n/**\n * Helper function to safely get the first path segment (component category)\n * from a component path. For \"ui/buttons/Button\" this returns \"ui\".\n *\n * @param componentPath - Component path string\n * @returns First segment of the path, or \"unknown\" if invalid\n */\nconst getComponentName = (componentPath: string): string => {\n if (!componentPath || typeof componentPath !== \"string\") {\n return \"unknown\";\n }\n const trimmed = componentPath.trim();\n if (!trimmed) return \"unknown\";\n const firstSlash = trimmed.indexOf(\"/\");\n return firstSlash === -1 ? trimmed : trimmed.slice(0, firstSlash);\n};\n\n/**\n * Tracks code copy events with validation.\n *\n * @param componentPath - Path of the component where code was copied\n */\nexport const googleTrackCodeCopy = (componentPath: string) => {\n if (!componentPath || typeof componentPath !== \"string\") {\n logger.warn(\"Analytics: componentPath is required for trackCodeCopy\");\n return;\n }\n\n const componentName = getComponentName(componentPath);\n googleTrackEvent({\n name: \"doc_copy\",\n properties: {\n component_name: componentName,\n content_type: \"code\",\n category: \"engagement\",\n label: `Code Copy - ${componentPath.trim()}`,\n },\n });\n};\n\n/**\n * Tracks theme mode changes with validation.\n *\n * @param componentPath - Path of the component where theme was changed\n * @param newTheme - New theme mode ('dark' or 'light')\n */\nexport const googleTrackThemeChange = (componentPath: string, newTheme: \"dark\" | \"light\") => {\n if (!componentPath || typeof componentPath !== \"string\") {\n logger.warn(\"Analytics: componentPath is required for trackThemeChange\");\n return;\n }\n\n if (!newTheme || ![\"dark\", \"light\"].includes(newTheme)) {\n logger.warn('Analytics: newTheme must be either \"dark\" or \"light\"');\n return;\n }\n\n const componentName = getComponentName(componentPath);\n googleTrackEvent({\n name: \"doc_select_theme\",\n properties: {\n component_name: componentName,\n theme_mode: newTheme,\n category: \"engagement\",\n label: `Theme Change - ${componentPath.trim()}`,\n },\n });\n};\n\n/**\n * Tracks text direction changes with validation.\n *\n * @param componentPath - Path of the component where direction was changed\n * @param newDirection - New text direction ('rtl' or 'ltr')\n */\nexport const googleTrackDirectionChange = (componentPath: string, newDirection: \"rtl\" | \"ltr\") => {\n if (!componentPath || typeof componentPath !== \"string\") {\n logger.warn(\"Analytics: componentPath is required for trackDirectionChange\");\n return;\n }\n\n if (!newDirection || ![\"rtl\", \"ltr\"].includes(newDirection)) {\n logger.warn('Analytics: newDirection must be either \"rtl\" or \"ltr\"');\n return;\n }\n\n const componentName = getComponentName(componentPath);\n googleTrackEvent({\n name: \"doc_select_direction\",\n properties: {\n component_name: componentName,\n text_direction: newDirection,\n category: \"engagement\",\n label: `Direction Change - ${componentPath.trim()}`,\n },\n });\n};\n\n/**\n * Tracks view mode changes with validation.\n *\n * @param componentPath - Path of the component where view was changed\n * @param newView - New view mode ('preview' or 'code')\n */\nexport const googleTrackViewChange = (componentPath: string, newView: \"preview\" | \"code\") => {\n if (!componentPath || typeof componentPath !== \"string\") {\n logger.warn(\"Analytics: componentPath is required for trackViewChange\");\n return;\n }\n\n if (!newView || ![\"preview\", \"code\"].includes(newView)) {\n logger.warn('Analytics: newView must be either \"preview\" or \"code\"');\n return;\n }\n\n const componentName = getComponentName(componentPath);\n googleTrackEvent({\n name: \"doc_select_view\",\n properties: {\n component_name: componentName,\n view_mode: newView,\n category: \"engagement\",\n label: `View Change - ${componentPath.trim()}`,\n },\n });\n};\n\n/**\n * Tracks item creation events with validation.\n *\n * @param module - Module name where item was created\n * @param itemType - Type of item created\n * @param itemId - Optional ID of the created item\n */\nexport const googleTrackItemCreate = (\n module: string,\n itemType: string,\n itemId?: string | number,\n) => {\n if (!module || typeof module !== \"string\" || module.trim().length === 0) {\n logger.warn(\"Analytics: module is required for trackItemCreate\");\n return;\n }\n\n if (!itemType || typeof itemType !== \"string\" || itemType.trim().length === 0) {\n logger.warn(\"Analytics: itemType is required for trackItemCreate\");\n return;\n }\n\n googleTrackEvent({\n name: \"crud_create\",\n properties: {\n module: module.trim(),\n item_type: itemType.trim(),\n ...(itemId && { item_id: itemId.toString() }),\n category: \"crud\",\n label: `Create ${itemType.trim()} - ${module.trim()}`,\n },\n });\n};\n\n/**\n * Tracks item view/read events with validation.\n *\n * @param module - Module name where item was viewed\n * @param itemType - Type of item viewed\n * @param itemId - ID of the viewed item\n */\nexport const googleTrackItemView = (module: string, itemType: string, itemId: string | number) => {\n if (!module || typeof module !== \"string\" || module.trim().length === 0) {\n logger.warn(\"Analytics: module is required for trackItemView\");\n return;\n }\n\n if (!itemType || typeof itemType !== \"string\" || itemType.trim().length === 0) {\n logger.warn(\"Analytics: itemType is required for trackItemView\");\n return;\n }\n\n if (itemId === undefined || itemId === null || itemId === \"\") {\n logger.warn(\"Analytics: itemId is required for trackItemView\");\n return;\n }\n\n googleTrackEvent({\n name: \"crud_view\",\n properties: {\n module: module.trim(),\n item_type: itemType.trim(),\n item_id: itemId.toString(),\n category: \"crud\",\n label: `View ${itemType.trim()} - ${module.trim()}`,\n },\n });\n};\n\n/**\n * Tracks item update events with validation.\n *\n * @param module - Module name where item was updated\n * @param itemType - Type of item updated\n * @param itemId - ID of the updated item\n */\nexport const googleTrackItemUpdate = (\n module: string,\n itemType: string,\n itemId: string | number,\n) => {\n if (!module || typeof module !== \"string\" || module.trim().length === 0) {\n logger.warn(\"Analytics: module is required for trackItemUpdate\");\n return;\n }\n\n if (!itemType || typeof itemType !== \"string\" || itemType.trim().length === 0) {\n logger.warn(\"Analytics: itemType is required for trackItemUpdate\");\n return;\n }\n\n if (itemId === undefined || itemId === null || itemId === \"\") {\n logger.warn(\"Analytics: itemId is required for trackItemUpdate\");\n return;\n }\n\n googleTrackEvent({\n name: \"crud_update\",\n properties: {\n module: module.trim(),\n item_type: itemType.trim(),\n item_id: itemId.toString(),\n category: \"crud\",\n label: `Update ${itemType.trim()} - ${module.trim()}`,\n },\n });\n};\n\n/**\n * Tracks item delete events with validation.\n *\n * @param module - Module name where item was deleted\n * @param itemType - Type of item deleted\n * @param itemId - ID of the deleted item\n * @param isHardDelete - Whether this is a hard delete (permanent) or soft delete\n */\nexport const googleTrackItemDelete = (\n module: string,\n itemType: string,\n itemId: string | number,\n isHardDelete: boolean = false,\n) => {\n if (!module || typeof module !== \"string\" || module.trim().length === 0) {\n logger.warn(\"Analytics: module is required for trackItemDelete\");\n return;\n }\n\n if (!itemType || typeof itemType !== \"string\" || itemType.trim().length === 0) {\n logger.warn(\"Analytics: itemType is required for trackItemDelete\");\n return;\n }\n\n if (itemId === undefined || itemId === null || itemId === \"\") {\n logger.warn(\"Analytics: itemId is required for trackItemDelete\");\n return;\n }\n\n googleTrackEvent({\n name: \"crud_delete\",\n properties: {\n module: module.trim(),\n item_type: itemType.trim(),\n item_id: itemId.toString(),\n delete_type: isHardDelete ? \"hard\" : \"soft\",\n category: \"crud\",\n label: `Delete ${itemType.trim()} - ${module.trim()}`,\n },\n });\n};\n\n/**\n * Tracks item restore events with validation.\n *\n * @param module - Module name where item was restored\n * @param itemType - Type of item restored\n * @param itemId - ID of the restored item\n */\nexport const googleTrackItemRestore = (\n module: string,\n itemType: string,\n itemId: string | number,\n) => {\n if (!module || typeof module !== \"string\" || module.trim().length === 0) {\n logger.warn(\"Analytics: module is required for trackItemRestore\");\n return;\n }\n\n if (!itemType || typeof itemType !== \"string\" || itemType.trim().length === 0) {\n logger.warn(\"Analytics: itemType is required for trackItemRestore\");\n return;\n }\n\n if (itemId === undefined || itemId === null || itemId === \"\") {\n logger.warn(\"Analytics: itemId is required for trackItemRestore\");\n return;\n }\n\n googleTrackEvent({\n name: \"crud_restore\",\n properties: {\n module: module.trim(),\n item_type: itemType.trim(),\n item_id: itemId.toString(),\n category: \"crud\",\n label: `Restore ${itemType.trim()} - ${module.trim()}`,\n },\n });\n};\n","/**\n * Utility function for array manipulation\n * Provides a way to split arrays into smaller chunks of specified size\n */\n\n/**\n * Splits an array into smaller chunks of a specified size\n * Useful for pagination, batch processing, or creating grid layouts\n *\n * @param array - The array to be chunked\n * @param chunk_size - The size of each chunk\n * @returns A new array containing chunks of the original array\n *\n * @example\n * ```ts\n * // Basic usage\n * chunk([1, 2, 3, 4, 5, 6, 7, 8], 3)\n * // Returns [[1, 2, 3], [4, 5, 6], [7, 8]]\n *\n * // With string array\n * chunk(['a', 'b', 'c', 'd', 'e'], 2)\n * // Returns [['a', 'b'], ['c', 'd'], ['e']]\n *\n * // With objects\n * const users = [\n * { id: 1, name: 'Alice' },\n * { id: 2, name: 'Bob' },\n * { id: 3, name: 'Charlie' },\n * { id: 4, name: 'Dave' }\n * ];\n * chunk(users, 2)\n * // Returns [\n * // [{ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' }],\n * // [{ id: 3, name: 'Charlie' }, { id: 4, name: 'Dave' }]\n * // ]\n *\n * // Empty array returns empty array\n * chunk([], 3)\n * // Returns []\n * ```\n */\nexport const chunk = <T>(array: T[], chunk_size: number): T[][] => {\n if (chunk_size <= 0) return [];\n return array.reduce((resultArray, item, index) => {\n const chunkIndex = Math.floor(index / chunk_size);\n\n if (!resultArray[chunkIndex]) {\n resultArray[chunkIndex] = []; // start a new chunk\n }\n\n resultArray[chunkIndex].push(item);\n\n return resultArray;\n }, [] as T[][]);\n};\n","/**\n * Utility function for random selection\n * Provides a simple way to select a random element from an array\n */\n\n/**\n * Selects a random element from an array\n * Returns undefined if the array is empty\n *\n * @param values - The array to select a random element from\n * @returns A random element from the array, or undefined if the array is empty\n *\n * @example\n * ```ts\n * import { randomValue } from '@/utils/functions';\n *\n * // Basic usage with strings\n * const colors = ['red', 'green', 'blue', 'yellow'];\n * const randomColor = randomValue(colors);\n * // Returns a random color from the array\n *\n * // With numbers\n * const randomNumber = randomValue([1, 2, 3, 4, 5]);\n * // Returns a random number from the array\n *\n * // With objects\n * const users = [\n * { id: 1, name: 'Alice' },\n * { id: 2, name: 'Bob' },\n * { id: 3, name: 'Charlie' }\n * ];\n * const randomUser = randomValue(users);\n * // Returns a random user object from the array\n *\n * // Handle empty array\n * const empty = [];\n * const result = randomValue(empty);\n * // Returns undefined\n *\n * // Type-safe with generics\n * const randomItem = randomValue<string>(['a', 'b', 'c']);\n * // TypeScript knows this is a string\n * ```\n */\nexport const randomValue = <T>(values: T[]): T | undefined => {\n if (values.length === 0) return undefined;\n return values[Math.floor(Math.random() * values.length)];\n};\n","/**\n * Utility function for stable array sorting\n * Provides a way to sort arrays while preserving the original order of equal elements\n */\n\n/**\n * Sorts an array using the specified compare function, preserving the order\n * of elements that compare equally (stable sort)\n *\n * @param arr - The array to sort\n * @param compare - The comparison function that returns negative, zero, or positive values\n * @returns A new sorted array with the original order of equal elements preserved\n *\n * @example\n * ```ts\n * import { stableSort } from '@/utils/functions';\n *\n * // Basic usage with numbers\n * const numbers = [3, 1, 4, 1, 5, 9];\n * const sortedNumbers = stableSort(numbers, (a, b) => a - b);\n * // Returns [1, 1, 3, 4, 5, 9] with the first \"1\" still coming before the second \"1\"\n *\n * // With objects and multiple sort criteria\n * const users = [\n * { name: 'Alice', role: 'admin', id: 1 },\n * { name: 'Bob', role: 'user', id: 2 },\n * { name: 'Charlie', role: 'user', id: 3 },\n * { name: 'David', role: 'admin', id: 4 }\n * ];\n *\n * // Sort by role first, then by original order\n * const sortedUsers = stableSort(users, (a, b) =>\n * a.role.localeCompare(b.role)\n * );\n * // The order of users with the same role is preserved\n * ```\n */\nexport const stableSort = <T>(arr: T[], compare: (a: T, b: T) => number): T[] =>\n arr\n .map((item, index) => ({ item, index }))\n .sort((a, b) => compare(a.item, b.item) || a.index - b.index)\n .map(({ item }) => item);\n","/**\n * Asset URL builder utilities\n * Provides helpers to construct absolute asset URLs against a configurable asset host.\n */\n\nimport { getEnv } from \"../../env\";\n\nconst DEFAULT_ASSET_HOST =\n getEnv(\"NEXT_PUBLIC_ASSETS_URL\") || getEnv(\"VITE_ASSETS_URL\") || \"https://assets.kumix.io\";\n\n/**\n * Builds an absolute URL for a given asset path using the provided asset host (CDN) base.\n * Accepts relative paths (e.g., `logo/logo.png`, `/images/icon.svg`) and returns a fully-qualified URL.\n * If an absolute URL is provided as `path`, it will be returned as-is (host is ignored).\n *\n * @param path - Asset path or absolute URL to resolve\n * @param host - Optional asset host (base URL). Defaults to `https://assets.kumix.io`\n * @returns A fully-qualified asset URL string. On invalid input (empty path or\n * malformed base), falls back to the configured asset host rather than\n * throwing — call sites that need strict failure should validate inputs first.\n *\n * @example\n * ```ts\n * import { assetsUrl } from '@/lib/assets';\n *\n * // Default host\n * const u1 = assetsUrl('logo/logo.png');\n * // 'https://assets.kumix.io/logo/logo.png'\n *\n * // Custom host (full URL)\n * const u2 = assetsUrl('/images/icon.svg', 'https://cdn.example.com');\n * // 'https://cdn.example.com/images/icon.svg'\n *\n * // Custom host (without protocol) — will be normalized to https://\n * const u3 = assetsUrl('icons/search.svg', 'cdn.example.com');\n * // 'https://cdn.example.com/icons/search.svg'\n *\n * // Absolute path passes through (host is ignored)\n * const u4 = assetsUrl('https://other.com/a.png', 'https://cdn.example.com');\n * // 'https://other.com/a.png'\n *\n * // Edge cases — falsy path or malformed base returns the configured asset host\n * const u5 = assetsUrl('');\n * // 'https://assets.kumix.io' (the configured host)\n *\n * const u6 = assetsUrl('logo.png', '://bad-host');\n * // '://bad-host' (the supplied host — invalid, returned as-is)\n * ```\n */\nexport function assetsUrl(path: string, host: string = DEFAULT_ASSET_HOST): string {\n const BASE_HOST = host;\n\n if (!path || typeof path !== \"string\") {\n return BASE_HOST;\n }\n\n try {\n // Normalize BASE_HOST if given without protocol, e.g., \"cdn.example.com\"\n const base = /^https?:\\/\\//i.test(BASE_HOST) ? BASE_HOST : `https://${BASE_HOST}`;\n const url = new URL(path, base); // absolute `path` will override `base`\n return url.toString();\n } catch {\n return BASE_HOST;\n }\n}\n\n/**\n * Build a CDN URL for a country flag SVG.\n *\n * The function lowercases the given ISO country code and returns a\n * fully-qualified URL pointing to the SVG flag hosted on the Kumix\n * assets CDN.\n *\n * @param flag - ISO 3166-1 alpha-2 country code (e.g., \"US\", \"ID\", \"GB\")\n * @returns A URL string to the SVG flag on the CDN\n *\n * @example\n * ```ts\n * import { getFlagUrl } from \"@kumix/ui/utils/flag-url\";\n *\n * const urlUs = getFlagUrl(\"US\");\n * // \"https://assets.kumix.io/media/flags/us.svg\"\n *\n * const urlId = getFlagUrl(\"id\");\n * // \"https://assets.kumix.io/media/flags/id.svg\"\n *\n * // Can be used directly in an <img /> or <Image /> component\n * // <img src={getFlagUrl(\"GB\")} alt=\"United Kingdom flag\" />\n * ```\n */\nexport function getFlagUrl(flag: string): string {\n // Guard against null/undefined/empty/non-string inputs — without this the\n // `.toLowerCase()` call throws and a bad flag code would otherwise produce a\n // malformed \".../.svg\" URL. Fall back to a deterministic placeholder.\n if (typeof flag !== \"string\" || !flag.trim()) {\n return `${assetsUrl(\"media/flags\")}/unknown.svg`;\n }\n const flagCode = flag.trim().toLowerCase();\n\n return `${assetsUrl(\"media/flags\")}/${flagCode}.svg`;\n}\n","/**\n * Browser metadata construction utilities\n * Provides functions for building SEO-optimized metadata for Next.js applications\n */\n\nimport { assetsUrl } from \"../string/assets\";\n\nexport type metadataProps = {\n baseUrl?: string;\n title?: string;\n fullTitle?: string;\n description?: string;\n // biome-ignore lint/suspicious/noExplicitAny: disable\n icons?: Array<Record<string, any>>;\n url?: string;\n image?: string | null;\n video?: string | null;\n openGraph?: {\n type?:\n | \"website\"\n | \"article\"\n | \"book\"\n | \"profile\"\n | \"music.song\"\n | \"music.album\"\n | \"music.playlist\"\n | \"music.radio_station\"\n | \"video.movie\"\n | \"video.episode\"\n | \"video.tv_show\"\n | \"video.other\";\n locale?: string;\n name?: string;\n };\n twitter?: {\n site?: string;\n creator?: string;\n };\n canonicalUrl?: string;\n alternateLanguages?: Record<string, string>;\n noIndex?: boolean;\n noArchive?: boolean;\n noSnippet?: boolean;\n manifest?: string | URL | null;\n};\n\n/**\n * Helper to map short locale codes to Open Graph/SEO locale format\n * @param locale - Short locale code (e.g., 'en', 'id', 'ar', 'zh')\n * @returns Open Graph locale string (e.g., 'en_US', 'id_ID', 'ar_AR', 'zh_CN')\n */\nexport function mapLocale(locale?: string): string | undefined {\n if (!locale) return \"en_US\";\n\n const mapping: Record<string, string> = {\n af: \"af_ZA\", // Afrikaans - South Africa\n am: \"am_ET\", // Amharic - Ethiopia\n ar: \"ar_AR\", // Arabic - Saudi Arabia\n bn: \"bn_BD\", // Bengali - Bangladesh\n bg: \"bg_BG\", // Bulgarian - Bulgaria\n cs: \"cs_CZ\", // Czech - Czech Republic\n da: \"da_DK\", // Danish - Denmark\n de: \"de_DE\", // German - Germany\n el: \"el_GR\", // Greek - Greece\n en: \"en_US\", // English - United States\n en_uk: \"en_GB\", // English - United Kingdom\n es: \"es_ES\", // Spanish - Spain\n es_mx: \"es_MX\", // Spanish - Mexico\n fa: \"fa_IR\", // Persian/Farsi - Iran\n fi: \"fi_FI\", // Finnish - Finland\n fr: \"fr_FR\", // French - France\n fr_ca: \"fr_CA\", // French - Canada\n he: \"he_IL\", // Hebrew - Israel\n hi: \"hi_IN\", // Hindi - India\n hr: \"hr_HR\", // Croatian - Croatia\n hu: \"hu_HU\", // Hungarian - Hungary\n id: \"id_ID\", // Indonesian - Indonesia\n it: \"it_IT\", // Italian - Italy\n ja: \"ja_JP\", // Japanese - Japan\n ko: \"ko_KR\", // Korean - South Korea\n ms: \"ms_MY\", // Malay - Malaysia\n nl: \"nl_NL\", // Dutch - Netherlands\n no: \"nb_NO\", // Norwegian Bokmål - Norway\n pl: \"pl_PL\", // Polish - Poland\n pt: \"pt_PT\", // Portuguese - Portugal\n pt_br: \"pt_BR\", // Portuguese - Brazil\n ro: \"ro_RO\", // Romanian - Romania\n ru: \"ru_RU\", // Russian - Russia\n sk: \"sk_SK\", // Slovak - Slovakia\n sr: \"sr_RS\", // Serbian - Serbia\n sv: \"sv_SE\", // Swedish - Sweden\n sw: \"sw_KE\", // Swahili - Kenya\n th: \"th_TH\", // Thai - Thailand\n tl: \"tl_PH\", // Filipino/Tagalog - Philippines\n tr: \"tr_TR\", // Turkish - Türkiye\n uk: \"uk_UA\", // Ukrainian - Ukraine\n ur: \"ur_PK\", // Urdu - Pakistan\n vi: \"vi_VN\", // Vietnamese - Vietnam\n zh: \"zh_CN\", // Chinese (Simplified) - China\n zh_hk: \"zh_HK\", // Chinese (Traditional) - Hong Kong\n zh_tw: \"zh_TW\", // Chinese (Traditional) - Taiwan\n };\n\n return mapping[locale] || locale;\n}\n\n/**\n * Constructs a metadata object for Next.js pages, suitable for SEO and social sharing.\n * Supports Open Graph, Twitter cards, icons, canonical URLs, robots, manifest, and multi-language alternates.\n *\n * @param params - Metadata construction options\n * @param params.baseUrl - The base URL/domain for metadataBase (optional, e.g., 'https://kumix.io')\n * @param params.title - The base title for the page (used in Open Graph and Twitter)\n * @param params.fullTitle - The full title for the page (overrides title in the <title> tag)\n * @param params.description - Description of the page (used in meta, Open Graph, Twitter)\n * @param params.icons - Icons for the page (favicon, apple-touch-icon, mask-icon, etc.)\n * @param params.url - The canonical URL of the page (used in Open Graph, canonical)\n * @param params.image - URL of the image for social sharing (Open Graph, Twitter)\n * @param params.video - URL of the video for social sharing (Open Graph, Twitter)\n * @param params.openGraph - Open Graph options (object: type, locale, name)\n * @param params.openGraph.type - Open Graph type (e.g., 'website', 'article', etc.)\n * @param params.openGraph.locale - Open Graph locale (e.g., 'en_US', 'id_ID')\n * @param params.openGraph.name - Open Graph site name (e.g., 'Kumix')\n * @param params.twitter - Twitter card options (object: site, creator)\n * @param params.twitter.site - Twitter @username for the site\n * @param params.twitter.creator - Twitter @username for the creator\n * @param params.canonicalUrl - Alternate canonical URL (used if url is not provided)\n * @param params.alternateLanguages - Object of language codes to URLs for alternate language versions\n * @param params.noIndex - If true, sets robots meta to noindex, nofollow (default: false)\n * @param params.noArchive - If true, sets robots meta to noarchive (default: false)\n * @param params.noSnippet - If true, sets robots meta to nosnippet (default: false)\n * @param params.manifest - URL or path to the web app manifest\n * @returns Metadata object compatible with Next.js <head> and SEO best practices\n *\n * @example\n * ```ts\n * import { constructMetadata } from '@/utils/functions';\n *\n * // Basic page metadata\n * const metadata = constructMetadata({\n * title: 'Home',\n * fullTitle: 'Kumix - Home',\n * description: 'Welcome to Kumix',\n * image: assetsUrl('og-image.png'),\n * url: '/home',\n * openGraph: {\n * type: 'website',\n * locale: 'en_US',\n * name: 'Kumix',\n * },\n * twitter: {\n * site: '@kumix',\n * creator: '@lukmanaviccena',\n * },\n * alternateLanguages: {\n * en: 'https://kumix.io/en',\n * id: 'https://kumix.io/id',\n * },\n * icons: [\n * { rel: 'icon', url: '/favicon.ico' },\n * { rel: 'mask-icon', url: '/safari-pinned-tab.svg', color: '#5bbad5' },\n * ],\n * });\n *\n * // Article metadata\n * const articleMetadata = constructMetadata({\n * title: 'How to Build Better Apps',\n * description: 'Learn the best practices for building modern web applications',\n * image: assetsUrl('articles/build-better-apps.pn'),\n * url: '/blog/build-better-apps',\n * openGraph: {\n * type: 'article',\n * locale: 'en_US',\n * name: 'Kumix Blog',\n * },\n * });\n *\n * // Product page metadata\n * const productMetadata = constructMetadata({\n * title: 'Premium Plan',\n * description: 'Unlock advanced features with our premium plan',\n * image: assetsUrl('products/premium.png'),\n * url: '/pricing/premium',\n * noIndex: false,\n * manifest: '/manifest.json',\n * });\n * ```\n */\nexport function constructMetadata({\n baseUrl,\n title,\n fullTitle,\n description,\n icons = [\n {\n rel: \"apple-touch-icon\",\n sizes: \"32x32\",\n url: assetsUrl(\"favicon/apple-touch-icon.png\"),\n },\n {\n rel: \"icon\",\n type: \"image/png\",\n sizes: \"32x32\",\n url: assetsUrl(\"favicon/favicon-32x32.png\"),\n },\n {\n rel: \"icon\",\n type: \"image/png\",\n sizes: \"16x16\",\n url: assetsUrl(\"favicon/favicon-16x16.png\"),\n },\n ],\n image,\n video,\n url,\n openGraph = {\n type: \"website\",\n locale: \"en_US\",\n },\n twitter = {},\n canonicalUrl,\n alternateLanguages,\n noIndex = false,\n noArchive = false,\n noSnippet = false,\n manifest,\n // biome-ignore lint/suspicious/noExplicitAny: disable\n}: metadataProps): Record<string, any> {\n // Build metadataBase defensively: a malformed baseUrl (common in dev, e.g.\n // NEXT_PUBLIC_SITE_URL=\"localhost:3000\" without protocol) used to throw and\n // 500 the page during Next.js metadata construction. Fall back to undefined.\n let metadataBase: URL | undefined;\n if (baseUrl) {\n try {\n metadataBase = new URL(baseUrl);\n } catch {\n metadataBase = undefined;\n }\n }\n\n return {\n metadataBase,\n title: fullTitle || title,\n description,\n icons,\n openGraph: {\n title,\n description,\n type: openGraph.type ?? \"website\",\n locale: mapLocale(openGraph.locale),\n ...(openGraph.name && {\n siteName: openGraph.name,\n }),\n url,\n ...(image && {\n images: image,\n }),\n ...(video && {\n videos: video,\n }),\n },\n twitter: {\n title,\n description,\n ...(image && {\n card: \"summary_large_image\",\n images: [image],\n }),\n ...(video && {\n player: video,\n }),\n ...(twitter.site && {\n site: twitter.site,\n }),\n ...(twitter.creator && {\n creator: twitter.creator,\n }),\n },\n ...((url || canonicalUrl || alternateLanguages) && {\n alternates: {\n ...(url || canonicalUrl ? { canonical: url || canonicalUrl } : {}),\n ...(alternateLanguages ? { languages: alternateLanguages } : {}),\n },\n }),\n ...((noIndex || noArchive || noSnippet) && {\n robots: {\n ...(noIndex ? { index: false, follow: false } : {}),\n ...(noArchive ? { noarchive: true } : {}),\n ...(noSnippet ? { nosnippet: true } : {}),\n },\n }),\n ...(manifest && {\n manifest,\n }),\n creator: \"lukmanaviccena\",\n };\n}\n","/**\n * Browser cookies utilities\n * Provides safe cookie operations with error handling and type safety\n * Works in both client-side and server-side environments\n */\n\nimport { logger } from \"../logging/logger\";\n\n/**\n * Interface for cookie options\n */\ninterface CookieOptions {\n /** Expiration time in days */\n expires?: number;\n /** Cookie path */\n path?: string;\n /** Cookie domain */\n domain?: string;\n /** Secure flag (HTTPS only) */\n secure?: boolean;\n /** SameSite attribute */\n sameSite?: \"strict\" | \"lax\" | \"none\";\n /** HttpOnly flag (server-side only) */\n httpOnly?: boolean;\n}\n\n/**\n * Interface for cookie value with metadata\n */\ninterface CookieValue<T = unknown> {\n /** The actual value */\n value: T;\n /** Timestamp when the cookie was set */\n timestamp: number;\n /** Optional version for data migration */\n version?: string;\n}\n\n/**\n * Sets a cookie with the specified name, value, and options\n * Automatically handles JSON serialization and error cases\n *\n * @param name - The name of the cookie\n * @param value - The value to store (will be JSON stringified)\n * @param options - Cookie options like expiration, path, domain, etc.\n * @returns True if the cookie was set successfully, false otherwise\n *\n * @example\n * ```typescript\n * import { setCookie } from '@kumix/utils';\n *\n * // Basic usage\n * setCookie('username', 'john_doe');\n *\n * // With expiration (7 days)\n * setCookie('auth_token', 'abc123', { expires: 7 });\n *\n * // With full options\n * setCookie('user_preferences', { theme: 'dark', lang: 'en' }, {\n * expires: 30,\n * path: '/',\n * secure: true,\n * sameSite: 'strict'\n * });\n *\n * // Store complex objects\n * setCookie('cart_items', [\n * { id: 1, name: 'Product A', quantity: 2 },\n * { id: 2, name: 'Product B', quantity: 1 }\n * ], { expires: 1 });\n *\n * // Session cookie (expires when browser closes)\n * setCookie('session_id', 'sess_123456');\n *\n * // Secure cookie for sensitive data\n * setCookie('csrf_token', 'token_abc', {\n * secure: true,\n * sameSite: 'strict',\n * httpOnly: true // Server-side only\n * });\n * ```\n */\nexport const setCookie = <T>(name: string, value: T, options: CookieOptions = {}): boolean => {\n if (typeof document === \"undefined\") {\n logger.warn(\"setCookie: Document is not available (SSR environment)\");\n return false;\n }\n\n try {\n const cookieValue: CookieValue<T> = {\n value,\n timestamp: Date.now(),\n version: \"1.0\",\n };\n\n const serializedValue = JSON.stringify(cookieValue);\n let cookieString = `${encodeURIComponent(name)}=${encodeURIComponent(serializedValue)}`;\n\n // Add expiration\n if (options.expires) {\n const expirationDate = new Date();\n expirationDate.setTime(expirationDate.getTime() + options.expires * 24 * 60 * 60 * 1000);\n cookieString += `; expires=${expirationDate.toUTCString()}`;\n }\n\n // Add path\n if (options.path) {\n cookieString += `; path=${options.path}`;\n }\n\n // Add domain\n if (options.domain) {\n cookieString += `; domain=${options.domain}`;\n }\n\n // Add secure flag\n if (options.secure) {\n cookieString += \"; secure\";\n }\n\n // Add SameSite\n if (options.sameSite) {\n cookieString += `; samesite=${options.sameSite}`;\n }\n\n // Add HttpOnly (note: this won't work in client-side JS, only server-side)\n if (options.httpOnly) {\n cookieString += \"; httponly\";\n }\n\n // biome-ignore lint/suspicious/noDocumentCookie: Legacy cookie API needed for broader browser compatibility\n document.cookie = cookieString;\n\n logger.debug(\"Cookie set successfully\", { name, options });\n return true;\n } catch (error) {\n logger.error(\"Failed to set cookie\", { name, error });\n return false;\n }\n};\n\n/**\n * Gets a cookie value by name with automatic JSON parsing\n * Returns null if the cookie doesn't exist or cannot be parsed\n *\n * @param name - The name of the cookie to retrieve\n * @returns The parsed cookie value or null if not found/invalid\n *\n * @example\n * ```typescript\n * import { getCookie } from '@kumix/utils';\n *\n * // Get simple value\n * const username = getCookie<string>('username');\n * if (username) {\n * console.log('Welcome back,', username);\n * }\n *\n * // Get complex object\n * const preferences = getCookie<{ theme: string; lang: string }>('user_preferences');\n * if (preferences) {\n * applyTheme(preferences.theme);\n * setLanguage(preferences.lang);\n * }\n *\n * // Get array data\n * const cartItems = getCookie<CartItem[]>('cart_items');\n * if (cartItems) {\n * updateCartDisplay(cartItems);\n * }\n *\n * // With default value\n * const theme = getCookie<string>('theme') || 'light';\n *\n * // Check if user is authenticated\n * const authToken = getCookie<string>('auth_token');\n * const isAuthenticated = !!authToken;\n *\n * // Get with type safety\n * interface UserSession {\n * userId: string;\n * role: string;\n * expiresAt: number;\n * }\n * const session = getCookie<UserSession>('user_session');\n * if (session && session.expiresAt > Date.now()) {\n * // Session is valid\n * authenticateUser(session);\n * }\n * ```\n */\nexport const getCookie = <T = unknown>(name: string): T | null => {\n if (typeof document === \"undefined\") {\n logger.warn(\"getCookie: Document is not available (SSR environment)\");\n return null;\n }\n\n try {\n const nameEQ = `${encodeURIComponent(name)}=`;\n const cookies = document.cookie.split(\";\");\n\n for (let cookie of cookies) {\n cookie = cookie.trim();\n if (cookie.indexOf(nameEQ) === 0) {\n const cookieValue = decodeURIComponent(cookie.substring(nameEQ.length));\n\n try {\n const parsed: CookieValue<T> = JSON.parse(cookieValue);\n logger.debug(\"Cookie retrieved successfully\", {\n name,\n timestamp: parsed.timestamp,\n version: parsed.version,\n });\n return parsed.value;\n } catch (_parseError) {\n // Fallback for cookies set without our wrapper\n logger.debug(\"Cookie found but not in expected format, returning raw value\", {\n name,\n });\n return cookieValue as T;\n }\n }\n }\n\n logger.debug(\"Cookie not found\", { name });\n return null;\n } catch (error) {\n logger.error(\"Failed to get cookie\", { name, error });\n return null;\n }\n};\n\n/**\n * Removes a cookie by setting its expiration date to the past\n * Optionally specify path and domain to ensure proper removal\n *\n * @param name - The name of the cookie to remove\n * @param options - Options for path and domain (should match the original cookie)\n * @returns True if the removal was attempted successfully, false otherwise\n *\n * @example\n * ```typescript\n * import { removeCookie } from '@kumix/utils';\n *\n * // Remove simple cookie\n * removeCookie('username');\n *\n * // Remove cookie with specific path\n * removeCookie('auth_token', { path: '/admin' });\n *\n * // Remove cookie with domain\n * removeCookie('session_id', {\n * path: '/',\n * domain: '.example.com'\n * });\n *\n * // Logout function\n * function logout() {\n * removeCookie('auth_token');\n * removeCookie('user_session');\n * removeCookie('csrf_token');\n * redirectToLogin();\n * }\n *\n * // Clear user preferences\n * function resetPreferences() {\n * removeCookie('user_preferences');\n * removeCookie('theme');\n * removeCookie('language');\n * applyDefaultSettings();\n * }\n *\n * // Clear shopping cart\n * function clearCart() {\n * removeCookie('cart_items');\n * removeCookie('cart_total');\n * updateCartDisplay([]);\n * }\n * ```\n */\nexport const removeCookie = (\n name: string,\n options: Pick<CookieOptions, \"path\" | \"domain\"> = {},\n): boolean => {\n if (typeof document === \"undefined\") {\n logger.warn(\"removeCookie: Document is not available (SSR environment)\");\n return false;\n }\n\n try {\n let cookieString = `${encodeURIComponent(name)}=; expires=Thu, 01 Jan 1970 00:00:00 UTC`;\n\n if (options.path) {\n cookieString += `; path=${options.path}`;\n }\n\n if (options.domain) {\n cookieString += `; domain=${options.domain}`;\n }\n\n // biome-ignore lint/suspicious/noDocumentCookie: Legacy cookie API needed for broader browser compatibility\n document.cookie = cookieString;\n\n logger.debug(\"Cookie removed successfully\", { name, options });\n return true;\n } catch (error) {\n logger.error(\"Failed to remove cookie\", { name, error });\n return false;\n }\n};\n\n/**\n * Checks if a cookie exists\n * More efficient than getCookie when you only need to check existence\n *\n * @param name - The name of the cookie to check\n * @returns True if the cookie exists, false otherwise\n *\n * @example\n * ```typescript\n * import { hasCookie } from '@kumix/utils';\n *\n * // Check if user is logged in\n * if (hasCookie('auth_token')) {\n * showDashboard();\n * } else {\n * showLoginForm();\n * }\n *\n * // Check for user preferences\n * if (hasCookie('user_preferences')) {\n * const prefs = getCookie('user_preferences');\n * applyPreferences(prefs);\n * } else {\n * showPreferencesSetup();\n * }\n *\n * // Conditional cookie setting\n * if (!hasCookie('visitor_id')) {\n * setCookie('visitor_id', generateVisitorId(), { expires: 365 });\n * }\n *\n * // Feature flag check\n * const hasFeatureFlag = hasCookie('feature_beta_enabled');\n * if (hasFeatureFlag) {\n * enableBetaFeatures();\n * }\n * ```\n */\nexport const hasCookie = (name: string): boolean => {\n if (typeof document === \"undefined\") {\n logger.warn(\"hasCookie: Document is not available (SSR environment)\");\n return false;\n }\n\n try {\n const nameEQ = `${encodeURIComponent(name)}=`;\n return document.cookie.split(\";\").some((cookie) => {\n return cookie.trim().indexOf(nameEQ) === 0;\n });\n } catch (error) {\n logger.error(\"Failed to check cookie existence\", { name, error });\n return false;\n }\n};\n\n/**\n * Gets all cookies as an object\n * Useful for debugging or bulk operations\n *\n * @returns Object containing all cookies with their parsed values\n *\n * @example\n * ```typescript\n * import { getAllCookies } from '@kumix/utils';\n *\n * // Get all cookies for debugging\n * const allCookies = getAllCookies();\n * console.log('Current cookies:', allCookies);\n *\n * // Check cookie count\n * const cookieCount = Object.keys(getAllCookies()).length;\n * if (cookieCount > 50) {\n * logger.warn('Too many cookies detected', { count: cookieCount });\n * }\n *\n * // Export user data\n * function exportUserData() {\n * const cookies = getAllCookies();\n * const userData = {\n * preferences: cookies.user_preferences,\n * settings: cookies.user_settings,\n * theme: cookies.theme\n * };\n * return userData;\n * }\n *\n * // Cookie audit\n * function auditCookies() {\n * const cookies = getAllCookies();\n * const report = {\n * total: Object.keys(cookies).length,\n * authRelated: Object.keys(cookies).filter(name =>\n * name.includes('auth') || name.includes('session')\n * ).length,\n * preferences: Object.keys(cookies).filter(name =>\n * name.includes('pref') || name.includes('setting')\n * ).length\n * };\n * return report;\n * }\n * ```\n */\nexport const getAllCookies = (): Record<string, unknown> => {\n if (typeof document === \"undefined\") {\n logger.warn(\"getAllCookies: Document is not available (SSR environment)\");\n return {};\n }\n\n try {\n const cookies: Record<string, unknown> = {};\n const cookieArray = document.cookie.split(\";\");\n\n for (let cookie of cookieArray) {\n cookie = cookie.trim();\n const [name, ...valueParts] = cookie.split(\"=\");\n\n if (name && valueParts.length > 0) {\n const value = valueParts.join(\"=\");\n const decodedName = decodeURIComponent(name);\n const decodedValue = decodeURIComponent(value);\n\n try {\n const parsed: CookieValue = JSON.parse(decodedValue);\n cookies[decodedName] = parsed.value;\n } catch {\n // Fallback for cookies not set with our wrapper\n cookies[decodedName] = decodedValue;\n }\n }\n }\n\n logger.debug(\"Retrieved all cookies\", {\n count: Object.keys(cookies).length,\n });\n return cookies;\n } catch (error) {\n logger.error(\"Failed to get all cookies\", { error });\n return {};\n }\n};\n\n/**\n * Clears all cookies for the current domain\n * Useful for logout or reset functionality\n *\n * @param options - Options for path and domain\n * @returns Number of cookies that were attempted to be removed\n *\n * @example\n * ```typescript\n * import { clearAllCookies } from '@kumix/utils';\n *\n * // Clear all cookies\n * const removedCount = clearAllCookies();\n * console.log(`Removed ${removedCount} cookies`);\n *\n * // Clear cookies for specific path\n * clearAllCookies({ path: '/admin' });\n *\n * // Complete logout function\n * function completeLogout() {\n * clearAllCookies();\n * localStorage.clear();\n * sessionStorage.clear();\n * redirectToLogin();\n * }\n *\n * // Reset application state\n * function resetApp() {\n * const cookieCount = clearAllCookies();\n * logger.info('Application reset', { cookiesRemoved: cookieCount });\n * window.location.reload();\n * }\n *\n * // Privacy compliance - clear tracking cookies\n * function clearTrackingCookies() {\n * const allCookies = getAllCookies();\n * const trackingCookies = Object.keys(allCookies).filter(name =>\n * name.includes('_ga') || name.includes('_gid') || name.includes('_fbp')\n * );\n *\n * trackingCookies.forEach(name => removeCookie(name));\n * return trackingCookies.length;\n * }\n * ```\n */\nexport const clearAllCookies = (options: Pick<CookieOptions, \"path\" | \"domain\"> = {}): number => {\n if (typeof document === \"undefined\") {\n logger.warn(\"clearAllCookies: Document is not available (SSR environment)\");\n return 0;\n }\n\n try {\n const cookies = getAllCookies();\n const cookieNames = Object.keys(cookies);\n\n cookieNames.forEach((name) => {\n removeCookie(name, options);\n });\n\n logger.info(\"Cleared all cookies\", {\n count: cookieNames.length,\n options,\n });\n return cookieNames.length;\n } catch (error) {\n logger.error(\"Failed to clear all cookies\", { error });\n return 0;\n }\n};\n","/**\n * Browser element height calculation utilities\n * Provides functions for measuring HTML element dimensions including margins\n */\n\n/**\n * Calculates the total height of an HTML element including its margins\n * This function computes the complete height of an element by combining:\n * - The element's content height (from getBoundingClientRect)\n * - Top margin\n * - Bottom margin\n *\n * This is useful for layout calculations where you need to know the total\n * space an element occupies, including its margins.\n *\n * @param element - The HTML element to measure\n * @returns The total height in pixels including margins, or 0 if element is null/undefined\n *\n * @example\n * ```ts\n * import { getHeight } from '@/utils/functions';\n *\n * // Basic usage\n * const button = document.querySelector('button');\n * const totalHeight = getHeight(button);\n * console.log(`Button takes up ${totalHeight}px of vertical space`);\n *\n * // Use in layout calculations\n * function calculateTotalHeight(elements: HTMLElement[]) {\n * return elements.reduce((total, element) => {\n * return total + getHeight(element);\n * }, 0);\n * }\n *\n * // Dynamic spacing for sticky headers\n * function adjustLayout() {\n * const header = document.querySelector('header') as HTMLElement;\n * const headerHeight = getHeight(header);\n * document.body.style.paddingTop = `${headerHeight}px`;\n * }\n *\n * // Responsive layout adjustments\n * function handleResize() {\n * const sidebar = document.querySelector('.sidebar') as HTMLElement;\n * const sidebarHeight = getHeight(sidebar);\n *\n * if (sidebarHeight > window.innerHeight) {\n * sidebar.style.overflowY = 'scroll';\n * }\n * }\n *\n * // Animation calculations\n * function animateCollapse(element: HTMLElement) {\n * const fullHeight = getHeight(element);\n * element.style.height = `${fullHeight}px`;\n * element.style.transition = 'height 0.3s ease';\n * element.style.height = '0px';\n * }\n * ```\n */\nexport function getHeight(element: HTMLElement): number {\n if (!element) return 0;\n if (typeof window === \"undefined\") return 0;\n\n const styles = window.getComputedStyle(element);\n\n const height = element.getBoundingClientRect().height;\n const marginTop = parseFloat(styles.marginTop);\n const marginBottom = parseFloat(styles.marginBottom);\n\n const totalHeight = height + marginTop + marginBottom;\n\n return totalHeight;\n}\n","/**\n * Utility function for client-side image resizing\n * Provides browser-based image resizing with aspect ratio handling\n */\n\n/**\n * Resizes an image file to specified dimensions while maintaining aspect ratio\n * Uses canvas to perform the resize operation in the browser\n *\n * @param file - The image File object to resize\n * @param opts - Resize options\n * @param opts.width - Target width in pixels (default: 1200)\n * @param opts.height - Target height in pixels (default: 630)\n * @param opts.quality - JPEG quality from 0.0 to 1.0 (default: 1.0)\n * @returns A Promise that resolves to a base64-encoded data URL of the resized image\n *\n * @example\n * ```ts\n * import { resizeImage } from '@/utils/functions';\n *\n * // Basic usage with a file from input\n * const fileInput = document.querySelector('input[type=\"file\"]');\n * fileInput.addEventListener('change', async (e) => {\n * const file = e.target.files[0];\n * if (file) {\n * try {\n * // Resize to default dimensions (1200x630)\n * const resizedImage = await resizeImage(file);\n *\n * // Display the resized image\n * const img = document.createElement('img');\n * img.src = resizedImage;\n * document.body.appendChild(img);\n * } catch (error) {\n * console.error('Image resize failed:', error);\n * }\n * }\n * });\n *\n * // With custom dimensions and quality\n * const thumbnail = await resizeImage(file, {\n * width: 300,\n * height: 200,\n * quality: 0.8\n * });\n *\n * // Use the resized image in an upload\n * const formData = new FormData();\n * formData.append('image', thumbnail);\n * await fetch('/api/upload', { method: 'POST', body: formData });\n * ```\n */\nexport const resizeImage = (\n file: File,\n opts: {\n width: number;\n height: number;\n quality?: number;\n } = {\n width: 1200,\n height: 630,\n quality: 1.0,\n },\n): Promise<string> => {\n if (typeof document === \"undefined\") {\n return Promise.reject(new Error(\"resizeImage only works in browser environments\"));\n }\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onload = (e: ProgressEvent<FileReader>) => {\n const img = new Image();\n // Attach load/error handlers BEFORE setting src. For cached images the\n // load event can fire synchronously after assigning src, and handlers\n // attached afterwards would miss it, leaving the promise pending forever.\n img.onload = () => {\n const targetWidth = opts.width;\n const targetHeight = opts.height;\n const canvas = document.createElement(\"canvas\");\n canvas.width = targetWidth;\n canvas.height = targetHeight;\n\n const ctx = canvas.getContext(\"2d\") as CanvasRenderingContext2D;\n ctx.imageSmoothingQuality = \"high\"; // Set image smoothing quality to high\n\n // Calculating the aspect ratio\n const sourceWidth = img.width;\n const sourceHeight = img.height;\n const sourceAspectRatio = sourceWidth / sourceHeight;\n const targetAspectRatio = targetWidth / targetHeight;\n\n let drawWidth: number;\n let drawHeight: number;\n let offsetX = 0;\n let offsetY = 0;\n\n // Adjust drawing sizes based on the aspect ratio\n if (sourceAspectRatio > targetAspectRatio) {\n // Source is wider\n drawHeight = sourceHeight;\n drawWidth = sourceHeight * targetAspectRatio;\n offsetX = (sourceWidth - drawWidth) / 2;\n } else {\n // Source is taller or has the same aspect ratio\n drawWidth = sourceWidth;\n drawHeight = sourceWidth / targetAspectRatio;\n offsetY = (sourceHeight - drawHeight) / 2;\n }\n\n // Draw the image onto the canvas\n ctx.drawImage(\n img,\n offsetX,\n offsetY,\n drawWidth,\n drawHeight,\n 0,\n 0,\n targetWidth,\n targetHeight,\n );\n\n // Convert the canvas to a base64 string\n const base64Image = canvas.toDataURL(\"image/jpeg\", opts.quality);\n resolve(base64Image);\n };\n img.onerror = (error) => reject(new Error(`Image loading error: ${error}`));\n img.src = e.target?.result as string;\n };\n reader.onerror = (error) => reject(new Error(`FileReader error: ${error}`));\n reader.readAsDataURL(file);\n });\n};\n\n/**\n * Resize and crop an image to a centered rectangle of the specified size.\n *\n * Processing steps:\n * - Load the image from the given `File`\n * - Determine target width & height from `size`\n * - `number` → width = height = value (e.g. `512`)\n * - `[width, height]` → explicit width & height (e.g. `[512, 1080]`)\n * - `null | undefined` → use the original image width & height\n * - Compute a centered crop region that matches the target aspect ratio\n * - Draw the cropped region to the canvas and export with desired format\n *\n * @param file The source image file to process\n * @param name The base name (without extension) for the output file\n * @param size Target size:\n * - `number` → square (width & height)\n * - `[width, height]` → custom rectangle\n * - `null | undefined` → use original image size\n * @param extension Output image extension (e.g., \"png\", \"jpeg\", \"webp\")\n * @returns A new `File` containing the processed image in the requested format\n *\n * @example\n * ```ts\n * // 1) Square: size = 512 → 512x512\n * const out1 = await resizeAndCropImage(file, \"avatar\", 512, \"webp\");\n *\n * // 2) Custom rectangle: size = [512, 1080] → 512x1080\n * const out2 = await resizeAndCropImage(file, \"poster\", [512, 1080], \"jpeg\");\n *\n * // 3) Keep original dimensions: size = null → originalWidth x originalHeight\n * const out3 = await resizeAndCropImage(file, \"original\", null, \"png\");\n * ```\n */\nexport async function resizeAndCropImage(\n file: File,\n name: string,\n size: number | [number, number] | null | undefined,\n extension: string,\n): Promise<File> {\n const image = await loadImage(file);\n\n // Determine target width & height based on `size` parameter\n let targetWidth: number;\n let targetHeight: number;\n\n if (Array.isArray(size)) {\n [targetWidth, targetHeight] = size;\n } else if (typeof size === \"number\") {\n targetWidth = size;\n targetHeight = size;\n } else {\n // When `size` is null or undefined, use original image dimensions\n targetWidth = image.width;\n targetHeight = image.height;\n }\n\n const canvas = document.createElement(\"canvas\");\n canvas.width = targetWidth;\n canvas.height = targetHeight;\n\n const ctx = canvas.getContext(\"2d\");\n\n // If we are using the original size, just draw the full image without cropping\n if (targetWidth === image.width && targetHeight === image.height) {\n ctx?.drawImage(image, 0, 0);\n } else {\n // Compute centered crop region based on aspect ratio (cover behavior)\n const sourceWidth = image.width;\n const sourceHeight = image.height;\n const sourceAspect = sourceWidth / sourceHeight;\n const targetAspect = targetWidth / targetHeight;\n\n let sx = 0;\n let sy = 0;\n let sWidth = sourceWidth;\n let sHeight = sourceHeight;\n\n if (targetAspect > sourceAspect) {\n // Target is wider → limit by width, crop top & bottom\n sWidth = sourceWidth;\n sHeight = sourceWidth / targetAspect;\n sy = (sourceHeight - sHeight) / 2;\n } else if (targetAspect < sourceAspect) {\n // Target is taller → limit by height, crop left & right\n sHeight = sourceHeight;\n sWidth = sourceHeight * targetAspect;\n sx = (sourceWidth - sWidth) / 2;\n }\n\n ctx?.drawImage(image, sx, sy, sWidth, sHeight, 0, 0, targetWidth, targetHeight);\n }\n\n const resizedImageBlob = await new Promise<Blob | null>((resolve) =>\n canvas.toBlob(resolve, `image/${extension}`),\n );\n\n return new File([resizedImageBlob as BlobPart], `${name}.${extension}`, {\n type: `image/${extension}`,\n });\n}\n\n/**\n * Load a `File` into an `HTMLImageElement` using `FileReader`\n *\n * Behavior:\n * - Reads the file as a Data URL and assigns it to `Image.src`\n * - Resolves once the image has fully loaded\n * - Rejects if the image fails to load\n *\n * @param file The image file to read and load\n * @returns A promise that resolves to an `HTMLImageElement` ready for drawing\n */\nexport async function loadImage(file: File): Promise<HTMLImageElement> {\n return new Promise((resolve, reject) => {\n const image = new Image();\n const reader = new FileReader();\n\n // Attach image handlers before the data URL is assigned to src to avoid\n // missing the load event on cached/instant-decode images.\n image.onload = () => resolve(image);\n image.onerror = (err) => reject(err);\n\n reader.onload = (e) => {\n image.src = e.target?.result as string;\n };\n\n reader.readAsDataURL(file);\n });\n}\n\n/**\n * Convert a `File` to a Base64-encoded Data URL string\n *\n * @param file The file to convert\n * @returns A promise that resolves to a Base64 Data URL string\n */\nexport async function fileToBase64(file: File): Promise<string> {\n return new Promise((resolve, reject) => {\n const reader = new FileReader();\n reader.onloadend = () => resolve(reader.result as string);\n reader.onerror = reject;\n reader.readAsDataURL(file);\n });\n}\n","/**\n * Browser storage utilities for React applications\n * Provides type-safe localStorage and sessionStorage operations\n * with SSR compatibility and error handling\n */\n\nimport { logger } from \"../logging/logger\";\n\n/**\n * Type representing browser storage options\n * Either localStorage (persists across sessions) or sessionStorage (cleared on tab close)\n */\ntype StorageType = \"localStorage\" | \"sessionStorage\";\n\n/**\n * Gets the appropriate Storage object based on the requested type\n *\n * @param storageType - Which storage type to use\n * @returns The Storage object or null if running in a non-browser environment\n */\nconst getStorageObject = (storageType: StorageType): Storage | null => {\n if (typeof window === \"undefined\") return null;\n return storageType === \"localStorage\" ? localStorage : sessionStorage;\n};\n\n/**\n * Retrieves data from browser storage with type safety\n *\n * @template T - The expected type of the stored data\n * @param key - The storage key to retrieve\n * @param storageType - Which storage to use (defaults to localStorage)\n * @param defaultValue - Value to return if key doesn't exist or on error\n * @returns The parsed data with type T, defaultValue, or undefined\n *\n * @example\n * ```typescript\n * // Get with type safety\n * const user = getStorageItem<User>('user');\n *\n * // With default value\n * const theme = getStorageItem<'light' | 'dark'>('theme', 'localStorage', 'light');\n *\n * // From session storage\n * const tempData = getStorageItem('tempData', 'sessionStorage');\n * ```\n */\nconst getStorageItem = <T = unknown>(\n key: string,\n storageType: StorageType = \"localStorage\",\n defaultValue?: T,\n): T | undefined => {\n try {\n const storage = getStorageObject(storageType);\n if (!storage) return defaultValue;\n\n const data = storage.getItem(key);\n if (data) {\n return JSON.parse(data) as T;\n }\n return defaultValue;\n } catch (error) {\n logger.error(`Read from ${storageType}`, error);\n return defaultValue;\n }\n};\n\n/**\n * Saves data to browser storage\n *\n * @param key - The storage key to set\n * @param value - The value to store (will be JSON stringified)\n * @param storageType - Which storage to use (defaults to localStorage)\n *\n * @example\n * ```typescript\n * // Save to localStorage\n * setStorageItem('user', { id: 1, name: 'John' });\n *\n * // Save to sessionStorage\n * setStorageItem('tempData', data, 'sessionStorage');\n * ```\n */\nconst setStorageItem = (\n key: string,\n value: unknown,\n storageType: StorageType = \"localStorage\",\n): void => {\n try {\n const storage = getStorageObject(storageType);\n if (!storage) return;\n\n storage.setItem(key, JSON.stringify(value));\n } catch (error) {\n logger.error(`Save in ${storageType}`, error);\n }\n};\n\n/**\n * Removes data from browser storage\n *\n * @param key - The storage key to remove\n * @param storageType - Which storage to use (defaults to localStorage)\n *\n * @example\n * ```typescript\n * // Remove from localStorage\n * removeStorageItem('user');\n *\n * // Remove from sessionStorage\n * removeStorageItem('tempData', 'sessionStorage');\n * ```\n */\nconst removeStorageItem = (key: string, storageType: StorageType = \"localStorage\"): void => {\n try {\n const storage = getStorageObject(storageType);\n if (!storage) return;\n\n storage.removeItem(key);\n } catch (error) {\n logger.error(`Remove from ${storageType}`, error);\n }\n};\n\n/**\n * Clears all data from the specified storage\n *\n * @param storageType - Which storage to clear (defaults to localStorage)\n *\n * @example\n * ```typescript\n * // Clear all localStorage\n * clearStorage();\n *\n * // Clear all sessionStorage\n * clearStorage('sessionStorage');\n * ```\n */\nconst clearStorage = (storageType: StorageType = \"localStorage\"): void => {\n try {\n const storage = getStorageObject(storageType);\n if (!storage) return;\n\n storage.clear();\n } catch (error) {\n logger.error(`Clear ${storageType}`, error);\n }\n};\n\n/**\n * Checks if a key exists in browser storage\n *\n * @param key - The storage key to check\n * @param storageType - Which storage to use (defaults to localStorage)\n * @returns Boolean indicating if the key exists\n *\n * @example\n * ```typescript\n * if (hasStorageItem('user')) {\n * // User data exists in localStorage\n * }\n *\n * if (hasStorageItem('session', 'sessionStorage')) {\n * // Session data exists in sessionStorage\n * }\n * ```\n */\nconst hasStorageItem = (key: string, storageType: StorageType = \"localStorage\"): boolean => {\n try {\n const storage = getStorageObject(storageType);\n if (!storage) return false;\n\n return storage.getItem(key) !== null;\n } catch (error) {\n logger.error(`Check ${storageType}`, error);\n return false;\n }\n};\n\nexport {\n clearStorage,\n getStorageItem,\n hasStorageItem,\n removeStorageItem,\n type StorageType,\n setStorageItem,\n};\n","/**\n * Utility functions for generating unique, time-sortable IDs\n * Provides ULID-compatible ID generation with custom prefixes for entity identification\n */\n\nconst prefixes = [\n \"acc_\", // account\n \"api_\", // api key\n \"ct_\", // contact\n \"cus_\", // customer\n \"dev_\", // device code\n \"elog_\", // email log\n \"org_\", // organization\n \"invi_\", // invitation\n \"mem_\", // member\n \"pass_\", // passkey\n \"prod_\", // product\n \"proj_\", // project\n \"rt_\", // rate limit\n \"sess_\", // session\n \"subs_\", // subscription\n \"two_\", // two factor auth\n \"user_\", // user\n \"ver_\", // verification token\n \"wh_\", // webhook\n \"ws_\", // workspace\n] as const;\n\n// Crockford base32 alphabet used by ULID\nconst CROCKFORD = \"0123456789ABCDEFGHJKMNPQRSTVWXYZ\";\n\n/**\n * Encodes a 16-byte (128-bit) buffer into a fixed-length 26-character\n * Crockford base32 ULID string. Unlike big-number base encoders, this pads\n * the output to a constant length so IDs remain lexicographically sortable\n * regardless of leading zero bytes.\n */\nfunction encodeULID(buf: Uint8Array): string {\n let bits = 0;\n let value = 0;\n let output = \"\";\n\n for (let i = 0; i < buf.length; i++) {\n value = (value << 8) | buf[i];\n bits += 8;\n while (bits >= 5) {\n bits -= 5;\n output += CROCKFORD[(value >>> bits) & 31];\n }\n }\n if (bits > 0) {\n output += CROCKFORD[(value << (5 - bits)) & 31];\n }\n\n return output;\n}\n\n/**\n * Creates a ULID-compatible buffer (48 bits timestamp + 80 bits randomness)\n *\n * @returns A 128-bit Uint8Array (6 bytes timestamp + 10 bytes randomness)\n */\nfunction createULIDBuffer(): Uint8Array {\n const buf = new Uint8Array(16); // 128 bits total\n\n // Timestamp (48 bits = 6 bytes)\n const timestamp = BigInt(Date.now());\n buf[0] = Number((timestamp >> BigInt(40)) & BigInt(255));\n buf[1] = Number((timestamp >> BigInt(32)) & BigInt(255));\n buf[2] = Number((timestamp >> BigInt(24)) & BigInt(255));\n buf[3] = Number((timestamp >> BigInt(16)) & BigInt(255));\n buf[4] = Number((timestamp >> BigInt(8)) & BigInt(255));\n buf[5] = Number(timestamp & BigInt(255));\n\n // Randomness (80 bits = 10 bytes)\n globalThis.crypto.getRandomValues(buf.subarray(6));\n\n return buf;\n}\n\n/**\n * Creates a unique, time-sortable ID with a custom prefix\n * Uses ULID format encoded in base32, making the IDs lexicographically sortable\n * by creation time and collision-resistant across distributed systems.\n *\n * @param prefix - Custom string to prepend to the generated ID\n * @returns A unique, time-sortable ID string prefixed with the given value\n *\n * @example\n * ```ts\n * import { baseIdCustom } from '@/utils/functions';\n *\n * // Generate ID with custom prefix\n * const teamId = baseIdCustom({ prefix: 'team_' });\n * // Example output: 'team_01H8XGJWBWBAQ4TPFV5JQ3PYJM'\n *\n * // Use for entities outside the predefined prefix set\n * const invoiceId = baseIdCustom({ prefix: 'inv_' });\n * const apiKey = baseIdCustom({ prefix: 'sk_' });\n * ```\n */\nexport const baseIdCustom = ({ prefix }: { prefix: string }) => {\n const buf = createULIDBuffer();\n const id = encodeULID(buf);\n\n return `${prefix}${id}`;\n};\n\n/**\n * Creates a unique, time-sortable ID with a known prefix from the predefined set\n * Wraps {@link baseIdCustom} with a constrained prefix type to enforce consistency\n * across the application.\n *\n * @param prefix - One of the predefined entity prefixes (e.g. `user_`, `org_`, `sess_`)\n * @returns A unique, time-sortable ID string prefixed with the given value\n *\n * @example\n * ```ts\n * import { baseId } from '@/utils/functions';\n *\n * // Generate IDs for common entity types\n * const userId = baseId({ prefix: 'user_' });\n * // Example output: 'user_01H8XGJWBWBAQ4TPFV5JQ3PYJM'\n *\n * const orgId = baseId({ prefix: 'org_' });\n * const sessionId = baseId({ prefix: 'sess_' });\n *\n * // Use in database models\n * const user = {\n * id: baseId({ prefix: 'user_' }),\n * name: 'John Doe',\n * email: 'john@example.com'\n * };\n * ```\n */\nexport const baseId = ({ prefix }: { prefix: (typeof prefixes)[number] }) =>\n baseIdCustom({ prefix });\n","/**\n * CUID (Collision-resistant Unique IDentifier) generation utilities\n * Provides functions for generating unique identifiers using @paralleldrive/cuid2\n */\n\nimport { createId, init } from \"@paralleldrive/cuid2\";\n\nexport { createId, init as initCuid };\n\n// Cache generators per length so we keep cuid2's internal fingerprint+counter\n// state across calls instead of recreating it on every invocation (which would\n// defeat cuid2's collision-resistance between rapid successive calls).\nconst generatorCache = new Map<number, (prefix?: string) => string>();\n\nfunction getGenerator(length: number): (prefix?: string) => string {\n let generator = generatorCache.get(length);\n if (!generator) {\n // NOTE: do NOT override `random` — cuid2 defaults to a cryptographically\n // secure RNG. Replacing it with Math.random makes IDs predictable.\n generator = init({ length });\n generatorCache.set(length, generator);\n }\n return generator;\n}\n\n/**\n * Generates a CUID (Collision-resistant Unique IDentifier)\n * CUIDs are designed to be globally unique, even in distributed systems.\n * They are based on the current time, a random component, and a counter.\n * Perfect for database IDs, session tokens, and any scenario requiring unique identifiers.\n *\n * @returns A CUID string\n *\n * @example\n * ```ts\n * import { cuid } from '@/utils/functions';\n *\n * // Generate a CUID\n * const id = cuid();\n * // Returns: 'clhqxr8kj0000qzrmn5t8b123'\n *\n * // Use as unique identifiers\n * const userId = cuid();\n * const sessionId = cuid();\n * const transactionId = cuid();\n *\n * // Use in database models\n * const user = {\n * id: cuid(),\n * name: 'John Doe',\n * email: 'john@example.com'\n * };\n *\n * // Use for temporary files\n * const tempFileName = `temp_${cuid()}.json`;\n * ```\n */\nexport function cuid() {\n return createId();\n}\n\n/**\n * Generates a custom ID with an optional prefix and configurable length.\n * Uses `@paralleldrive/cuid2`'s cryptographically-secure RNG.\n *\n * @param prefix - Optional prefix to prepend to the ID\n * @param length - The length of the generated ID (default is 12)\n * @returns A unique custom ID string\n *\n * @example\n * ```ts\n * import { customId } from '@/utils/functions';\n *\n * // Generate ID with prefix\n * const userId = customId('user_');\n * // Returns: 'user_l5r8xn2gzqnb'\n *\n * // Generate ID with custom length\n * const orderId = customId('order_', 16);\n * ```\n */\nexport function customId(prefix?: string, length: number = 12) {\n const generateId = getGenerator(length);\n return `${prefix || \"\"}${generateId()}`;\n}\n\n/**\n * @deprecated Use {@link customId} instead. This alias has a typo and is kept\n * only for backward compatibility; it will be removed in a future major.\n */\nexport const customeId = customId;\n","/**\n * Utility function for cryptographic hashing\n * Provides secure string hashing using the SHA-256 algorithm\n */\n\n/**\n * Hashes a string using the SHA-256 algorithm\n * Uses the Web Crypto API for secure cryptographic operations\n *\n * @param str - The string to hash\n * @returns A Promise that resolves to the hexadecimal representation of the hash\n *\n * @example\n * ```ts\n * import { hashStringSHA256 } from '@/utils/functions';\n *\n * // Basic usage\n * const hash = await hashStringSHA256('hello world');\n * // Returns \"b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9\"\n *\n * // For password verification (example only - use proper password hashing in production)\n * async function verifyPassword(inputPassword: string, storedHash: string) {\n * const inputHash = await hashStringSHA256(inputPassword);\n * return inputHash === storedHash;\n * }\n *\n * // For data integrity verification\n * async function verifyDataIntegrity(data: string, expectedHash: string) {\n * const actualHash = await hashStringSHA256(data);\n * return actualHash === expectedHash;\n * }\n * ```\n */\nexport async function hashStringSHA256(str: string): Promise<string> {\n // Encode the string into bytes\n const encoder = new TextEncoder();\n const data = encoder.encode(str);\n\n // Hash the data with SHA-256\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n\n // Convert the buffer to a hexadecimal string\n const hashArray = Array.from(new Uint8Array(hashBuffer));\n const hashHex = hashArray.map((b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n\n return hashHex;\n}\n","/**\n * Utility function for generating unique IDs\n * Provides a wrapper around nanoid for consistent ID generation\n */\n\nimport { customAlphabet } from \"nanoid\";\n\nconst DEFAULT_ALPHABET = \"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz\";\nconst DEFAULT_SIZE = 7;\n\n/**\n * Generates a random alphanumeric ID of specified length\n * Uses a custom alphabet of numbers and letters (both cases)\n *\n * @param chars - The length of the ID to generate (default: 7)\n * @returns A random alphanumeric string of the specified length\n *\n * @example\n * ```ts\n * import { nanoid } from '@/utils/functions';\n *\n * // Generate default 7-character ID\n * const id = nanoid();\n * // Example output: \"a1B2c3D\"\n *\n * // Generate custom length ID\n * const longerId = nanoid(12);\n * // Example output: \"a1B2c3D4e5F6\"\n *\n * // Use as unique identifiers\n * const userId = nanoid();\n * const sessionId = nanoid(10);\n * ```\n */\nexport const nanoid = (chars?: number): string => {\n return customAlphabet(DEFAULT_ALPHABET, chars || DEFAULT_SIZE)();\n};\n\n/**\n * Generates a unique identifier using the current timestamp and a random number\n *\n * This function creates a simple unique ID by combining the current timestamp\n * with a random number. While not cryptographically secure, it's suitable for\n * most UI purposes like generating keys for React components.\n *\n * @returns A string representing the unique ID\n *\n * @example\n * ```typescript\n * // Generate unique IDs for React keys\n * const items = data.map(item => ({\n * ...item,\n * id: uid()\n * }));\n *\n * // Generate unique form field IDs\n * const fieldId = uid();\n * <input id={fieldId} />\n * <label htmlFor={fieldId}>Label</label>\n *\n * // Generate unique component keys\n * {items.map(item => (\n * <Component key={uid()} {...item} />\n * ))}\n * ```\n */\nexport function uid(): string {\n // Concatenate (not add) the timestamp with a zero-padded random suffix so IDs\n // generated within the same millisecond don't collide. Adding the random\n // value to the timestamp (the previous behavior) produced heavy collisions.\n const random = Math.floor(Math.random() * 1000)\n .toString()\n .padStart(3, \"0\");\n return `${Date.now()}${random}`;\n}\n","/**\n * Utility functions for billing date calculations\n * Provides tools for determining billing cycles, adjusting for month lengths, etc.\n */\n\n/**\n * Gets the last day of the current month\n *\n * @param referenceDate - Optional reference date (defaults to current date)\n * @returns The number representing the last day of the month (28-31)\n *\n * @example\n * ```ts\n * // If current month is February 2023\n * getLastDayOfMonth()\n * // Returns 28\n *\n * // If current month is January 2023\n * getLastDayOfMonth()\n * // Returns 31\n *\n * // With specific reference date\n * getLastDayOfMonth(new Date('2023-02-15'))\n * // Returns 28\n * ```\n */\nexport const getLastDayOfMonth = (referenceDate: Date = new Date()): number => {\n const lastDay = new Date(referenceDate.getFullYear(), referenceDate.getMonth() + 1, 0); // This will give the last day of the current month\n return lastDay.getDate();\n};\n\n/**\n * Adjusts the billing cycle start day based on the number of days in the current month\n * Ensures billing cycle start day is valid for months with fewer days\n *\n * @param billingCycleStart - The preferred billing cycle start day (1-31)\n * @param referenceDate - Optional reference date (defaults to current date)\n * @returns An adjusted billing cycle start day that is valid for the current month\n *\n * @example\n * ```ts\n * // If billing cycle starts on the 30th, but current month is February\n * getAdjustedBillingCycleStart(30)\n * // Returns 28 (or 29 in leap years)\n *\n * // If billing cycle starts on the 30th, and current month is January\n * getAdjustedBillingCycleStart(30)\n * // Returns 30 (no adjustment needed)\n *\n * // With specific reference date\n * getAdjustedBillingCycleStart(30, new Date('2023-02-15'))\n * // Returns 28\n * ```\n */\nexport const getAdjustedBillingCycleStart = (\n billingCycleStart: number,\n referenceDate: Date = new Date(),\n): number => {\n const lastDay = getLastDayOfMonth(referenceDate);\n if (billingCycleStart > lastDay) {\n return lastDay;\n } else {\n return billingCycleStart;\n }\n};\n\n/**\n * Calculates the start date of the current billing period\n * Based on the billing cycle start day and the current date\n *\n * @param billingCycleStart - The day of the month when billing cycle starts (1-31)\n * @param referenceDate - Optional reference date (defaults to current date)\n * @returns A Date object representing the start of the current billing period\n *\n * @example\n * ```ts\n * // If today is January 15, 2023 and billing cycle starts on the 10th\n * getBillingStartDate(10)\n * // Returns new Date(\"2023-01-10\") (current month's billing start)\n *\n * // If today is January 5, 2023 and billing cycle starts on the 10th\n * getBillingStartDate(10)\n * // Returns new Date(\"2022-12-10\") (previous month's billing start)\n *\n * // With billing cycle start day that exceeds days in some months (e.g., 31)\n * getBillingStartDate(31, new Date('2023-03-15'))\n * // Returns new Date(\"2023-02-28\") (adjusted for February)\n *\n * // With specific reference date\n * getBillingStartDate(15, new Date('2023-01-20'))\n * // Returns new Date(\"2023-01-15\")\n * ```\n */\nexport const getBillingStartDate = (\n billingCycleStart: number,\n referenceDate: Date = new Date(),\n): Date => {\n const today = referenceDate;\n const currentDay = today.getDate();\n const currentMonth = today.getMonth();\n const currentYear = today.getFullYear();\n const adjustedBillingCycleStart = getAdjustedBillingCycleStart(billingCycleStart, referenceDate);\n if (currentDay <= adjustedBillingCycleStart) {\n // if the current day is less than the billing cycle start, we need to go back a month\n const lastMonth = currentMonth === 0 ? 11 : currentMonth - 1; // if the current month is January, we need to go back to December\n const lastYear = currentMonth === 0 ? currentYear - 1 : currentYear; // if the current month is January, we need to go back a year\n return new Date(lastYear, lastMonth, adjustedBillingCycleStart);\n } else {\n return new Date(currentYear, currentMonth, adjustedBillingCycleStart);\n }\n};\n","/**\n * Utility function for formatting dates in a consistent way\n * Provides human-readable date formatting with customizable options\n */\n\n/**\n * Formats a date into a localized string representation\n *\n * @param datetime - The date to format (can be Date object or string)\n * @param options - Optional Intl.DateTimeFormat options to customize formatting\n * @param locale - Optional locale string (defaults to 'en-US')\n * @returns A formatted date string, or empty string if date is invalid\n *\n * @example\n * ```ts\n * // Basic usage with defaults\n * formatDate(new Date('2023-01-15'))\n * // Returns \"January 15, 2023\"\n *\n * // With a date string\n * formatDate('2023-01-15')\n * // Returns \"January 15, 2023\"\n *\n * // With custom options\n * formatDate(new Date('2023-01-15'), {\n * month: 'short',\n * day: '2-digit'\n * })\n * // Returns \"Jan 15, 2023\"\n *\n * // With custom locale\n * formatDate(new Date('2023-01-15'), undefined, 'de-DE')\n * // Returns \"15. Januar 2023\"\n *\n * // With custom locale and options\n * formatDate(new Date('2023-01-15'), {\n * weekday: 'long',\n * year: 'numeric',\n * month: 'long',\n * day: 'numeric'\n * }, 'fr-FR')\n * // Returns \"dimanche 15 janvier 2023\"\n *\n * // With invalid date\n * formatDate('invalid-date')\n * // Returns \"\"\n * ```\n */\nexport const formatDate = (\n datetime: Date | string,\n options?: Intl.DateTimeFormatOptions,\n locale: string = \"en-US\",\n): string => {\n const date = new Date(datetime);\n if (Number.isNaN(date.getTime())) return \"\";\n return date.toLocaleDateString(locale, {\n day: \"numeric\",\n month: \"long\",\n year: \"numeric\",\n ...options,\n });\n};\n","/**\n * Utility function for smart date and time formatting\n * Provides context-aware datetime formatting based on date proximity to current time\n */\n\n/**\n * Formats a date intelligently - shows year for past years, shows time for current year\n *\n * @param datetime - The date to format (can be Date object or string)\n * @param options - Optional Intl.DateTimeFormat options to customize formatting\n * @param locale - Optional locale string (defaults to 'en-US')\n * @returns A formatted date string with contextual information\n *\n * @example\n * ```ts\n * // For a date in the current year (assuming current year is 2023)\n * formatDateTimeSmart(new Date('2023-06-15'))\n * // Returns \"Jun 15, 10:30 AM\" (with time)\n *\n * // For a date in a previous year\n * formatDateTimeSmart(new Date('2022-06-15'))\n * // Returns \"Jun 15, 2022\" (with year instead of time)\n *\n * // With custom options\n * formatDateTimeSmart(new Date('2022-06-15'), {\n * weekday: 'long'\n * })\n * // Returns \"Wednesday, Jun 15, 2022\"\n *\n * // With custom locale\n * formatDateTimeSmart(new Date('2022-06-15'), undefined, 'fr-FR')\n * // Returns \"15 juin 2022\"\n *\n * // Current year with custom locale\n * formatDateTimeSmart(new Date('2023-06-15'), undefined, 'de-DE')\n * // Returns \"15. Jun, 10:30\" (format depends on locale)\n * ```\n */\nexport const formatDateTimeSmart = (\n datetime: Date | string,\n options?: Intl.DateTimeFormatOptions,\n locale: string = \"en-US\",\n): string => {\n const date = new Date(datetime);\n if (Number.isNaN(date.getTime())) {\n return \"Invalid Date\";\n }\n const now = new Date();\n\n // Use the same timezone basis for the year comparison and the formatting so\n // a date near midnight doesn't compare as a different year than it displays.\n return new Date(datetime).toLocaleDateString(locale, {\n month: \"short\",\n day: \"numeric\",\n ...(date.getFullYear() !== now.getFullYear()\n ? { year: \"numeric\" }\n : {\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n }),\n ...options,\n });\n};\n","/**\n * Utility function for formatting date and time in a consistent way\n * Provides human-readable datetime formatting with customizable options\n */\n\n/**\n * Formats a date and time into a localized string representation\n *\n * @param datetime - The date to format (can be Date object or string)\n * @param options - Optional Intl.DateTimeFormat options to customize formatting\n * @param locale - Optional locale string (defaults to 'en-US')\n * @returns A formatted date and time string, or empty string if date is invalid\n *\n * @example\n * ```ts\n * // Basic usage with defaults\n * formatDateTime(new Date('2023-01-15T14:30:00'))\n * // Returns \"Jan 15, 2023, 2:30 PM\"\n *\n * // With a date string\n * formatDateTime('2023-01-15T14:30:00')\n * // Returns \"Jan 15, 2023, 2:30 PM\"\n *\n * // With custom options\n * formatDateTime(new Date('2023-01-15T14:30:00'), {\n * weekday: 'long',\n * second: 'numeric'\n * })\n * // Returns \"Sunday, Jan 15, 2023, 2:30:00 PM\"\n *\n * // With 24-hour format\n * formatDateTime(new Date('2023-01-15T14:30:00'), {\n * hour12: false\n * })\n * // Returns \"Jan 15, 2023, 14:30\"\n *\n * // With custom locale\n * formatDateTime(new Date('2023-01-15T14:30:00'), undefined, 'de-DE')\n * // Returns \"15. Jan 2023, 14:30\"\n *\n * // With invalid date\n * formatDateTime('invalid-date')\n * // Returns \"\"\n * ```\n */\nexport const formatDateTime = (\n datetime: Date | string,\n options?: Intl.DateTimeFormatOptions,\n locale: string = \"en-US\",\n): string => {\n const date = new Date(datetime);\n if (Number.isNaN(date.getTime())) return \"\";\n return date.toLocaleString(locale, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n ...options,\n });\n};\n","/**\n * Utility function for formatting date periods/ranges\n * Provides consistent date range formatting with smart year display\n */\n\nimport { formatDate } from \"./format-date\";\n\n/**\n * Formats a date period (start and end dates) into a readable range string\n * Shows year only when start and end dates are in different years\n *\n * @param d - Object containing period information\n * @param d.periodStart - Start date of the period\n * @param d.periodEnd - End date of the period\n * @param locale - Optional locale string for date formatting (defaults to 'en-US')\n * @returns A formatted date period string, or '-' if dates are missing\n *\n * @example\n * ```ts\n * // For dates in the same year\n * formatPeriod({\n * periodStart: new Date('2023-01-15'),\n * periodEnd: new Date('2023-06-30')\n * })\n * // Returns \"Jan-Jun\"\n *\n * // For dates in different years\n * formatPeriod({\n * periodStart: new Date('2022-11-01'),\n * periodEnd: new Date('2023-02-28')\n * })\n * // Returns \"Nov 2022-Feb\"\n *\n * // With custom locale\n * formatPeriod({\n * periodStart: new Date('2022-11-01'),\n * periodEnd: new Date('2023-02-28')\n * }, 'fr-FR')\n * // Returns \"nov. 2022-févr.\"\n *\n * // With missing dates\n * formatPeriod({\n * periodStart: null,\n * periodEnd: new Date('2023-02-28')\n * })\n * // Returns \"-\"\n * ```\n */\nexport const formatPeriod = (\n d: {\n periodStart?: Date | null;\n periodEnd?: Date | null;\n },\n locale: string = \"en-US\",\n): string => {\n if (!d.periodStart || !d.periodEnd) {\n return \"-\";\n }\n\n return `${formatDate(\n d.periodStart,\n {\n month: \"short\",\n year:\n new Date(d.periodStart).getUTCFullYear() === new Date(d.periodEnd).getUTCFullYear()\n ? undefined\n : \"numeric\",\n timeZone: \"utc\",\n },\n locale,\n )}-${formatDate(\n d.periodEnd,\n {\n month: \"short\",\n timeZone: \"utc\",\n },\n locale,\n )}`;\n};\n","/**\n * Utility function for formatting time in a consistent way\n * Provides human-readable time formatting with customizable options\n */\n\n/**\n * Formats a time as a readable string in \"Hour:Minute AM/PM\" format\n *\n * Extracts and formats only the time portion from a date object or string.\n * Uses 12-hour format with AM/PM indicators for better readability.\n *\n * @param date - A date object or string to format\n * @param locale - The locale for formatting (defaults to 'en-US')\n * @returns A string formatted as \"Hour:Minute AM/PM\"\n *\n * @example\n * ```typescript\n * // Using default locale\n * formatTime(new Date()); // \"2:30 PM\"\n *\n * // Using specific locale\n * formatTime(new Date(), 'id-ID'); // \"14.30\"\n * formatTime(new Date(), 'de-DE'); // \"14:30\"\n *\n * // With date string\n * formatTime('2023-12-25T14:30:00'); // \"2:30 PM\"\n * ```\n */\nexport const formatTime = (date: Date | string, locale: string = \"en-US\"): string => {\n const parsedDate = typeof date === \"string\" ? new Date(date) : date;\n return new Intl.DateTimeFormat(locale, {\n hour: \"numeric\",\n minute: \"numeric\",\n hour12: true,\n }).format(parsedDate);\n};\n","/**\n * Utility function for formatting dates in HTML datetime-local input format\n * Provides consistent datetime string formatting for form inputs\n */\n\n/**\n * Converts a date to a string format compatible with HTML datetime-local inputs\n * Format returned is YYYY-MM-DDThh:mm (compatible with <input type=\"datetime-local\">)\n *\n * @param timestamp - Optional date to format (defaults to current date/time)\n * @returns A string in datetime-local format (YYYY-MM-DDThh:mm), or empty string if date is invalid\n *\n * @example\n * ```ts\n * // Current date/time in datetime-local format\n * getDateTimeLocal()\n * // Returns something like \"2023-06-15T14:30\" (current time)\n *\n * // Specific date in datetime-local format\n * getDateTimeLocal(new Date('2023-06-15T14:30:00'))\n * // Returns \"2023-06-15T14:30\"\n *\n * // With invalid date\n * getDateTimeLocal(new Date('invalid'))\n * // Returns \"\"\n *\n * // Usage with HTML input\n * // <input\n * // type=\"datetime-local\"\n * // value={getDateTimeLocal(startDate)}\n * // onChange={(e) => setStartDate(new Date(e.target.value))}\n * // />\n * ```\n */\nexport const getDateTimeLocal = (timestamp?: Date): string => {\n const d = timestamp ? new Date(timestamp) : new Date();\n if (d.toString() === \"Invalid Date\") return \"\";\n return new Date(d.getTime() - d.getTimezoneOffset() * 60000)\n .toISOString()\n .split(\":\")\n .slice(0, 2)\n .join(\":\");\n};\n","/**\n * Utility function for calculating the difference between dates in days\n * Provides accurate day count calculations for date ranges\n */\n\n/**\n * Calculates the number of days between two dates\n * Returns the absolute difference regardless of which date comes first\n *\n * @param startDate - The first date in the comparison\n * @param endDate - The second date in the comparison\n * @returns The number of days between the two dates (always positive)\n *\n * @example\n * ```ts\n * // Basic usage\n * getDaysDifference(\n * new Date('2023-01-01'),\n * new Date('2023-01-10')\n * )\n * // Returns 9\n *\n * // Order of dates doesn't matter (result is always positive)\n * getDaysDifference(\n * new Date('2023-01-10'),\n * new Date('2023-01-01')\n * )\n * // Returns 9\n *\n * // With time components\n * getDaysDifference(\n * new Date('2023-01-01T10:00:00'),\n * new Date('2023-01-02T08:00:00')\n * )\n * // Returns 1 (rounds up to the nearest day)\n *\n * // Across month boundaries\n * getDaysDifference(\n * new Date('2023-01-28'),\n * new Date('2023-02-05')\n * )\n * // Returns 8\n * ```\n */\nexport const getDaysDifference = (startDate: Date, endDate: Date): number => {\n const diffTime = Math.abs(endDate.getTime() - startDate.getTime());\n return Math.ceil(diffTime / (1000 * 60 * 60 * 24));\n};\n","/**\n * Utility function for calculating billing or subscription periods\n * Provides date range calculations based on a specific day of the month\n */\n\n/**\n * Calculates the first and last day of a period based on a specific day of the month\n * Useful for determining billing cycles, subscription periods, etc.\n *\n * @param day - The day of the month that marks the boundary of the period (1-31)\n * @param referenceDate - Optional reference date (defaults to current date)\n * @returns An object containing the first and last day of the period\n *\n * @example\n * ```ts\n * // If today is May 20, 2023 and the billing day is the 15th\n * getFirstAndLastDay(15)\n * // Returns:\n * // {\n * // firstDay: new Date(\"2023-05-15T00:00:00\"), // May 15, 2023\n * // lastDay: new Date(\"2023-06-14T00:00:00\") // June 14, 2023\n * // }\n *\n * // If today is May 10, 2023 and the billing day is the 15th\n * getFirstAndLastDay(15)\n * // Returns:\n * // {\n * // firstDay: new Date(\"2023-04-15T00:00:00\"), // April 15, 2023\n * // lastDay: new Date(\"2023-05-14T00:00:00\") // May 14, 2023\n * // }\n *\n * // With a specific reference date\n * getFirstAndLastDay(15, new Date('2023-05-20'))\n * // Returns the same result as the first example\n * ```\n */\nexport const getFirstAndLastDay = (\n day: number,\n referenceDate: Date = new Date(),\n): { firstDay: Date; lastDay: Date } => {\n const today = referenceDate;\n const currentDay = today.getDate();\n const currentMonth = today.getMonth();\n const currentYear = today.getFullYear();\n\n // Cap the requested day to the last day of a given (year, month) so that\n // boundary values like 31 don't roll over into the next month\n // (e.g. Feb 31 → Mar 3 in naive `new Date(year, month, day)`).\n const lastDayOfMonth = (year: number, month: number) => new Date(year, month + 1, 0).getDate();\n const clamp = (year: number, month: number, requested: number) =>\n Math.min(requested, lastDayOfMonth(year, month));\n\n if (currentDay >= day) {\n // we just passed `day` earlier this period — current period starts on `day`\n const firstDayClamped = clamp(currentYear, currentMonth, day);\n const lastMonth = currentMonth + 1;\n const lastYear = currentYear + (currentMonth === 11 ? 1 : 0);\n // lastDay = day - 1 of next month, but clamp in case next month is shorter\n const lastDayClamped = clamp(\n lastMonth === 12 ? lastYear : currentYear,\n lastMonth % 12,\n Math.max(1, day - 1),\n );\n return {\n firstDay: new Date(currentYear, currentMonth, firstDayClamped),\n lastDay: new Date(lastMonth === 12 ? lastYear : currentYear, lastMonth % 12, lastDayClamped),\n };\n }\n // we haven't reached `day` yet — current period started in the previous month\n const lastYear = currentMonth === 0 ? currentYear - 1 : currentYear;\n const lastMonth = currentMonth === 0 ? 11 : currentMonth - 1;\n const firstDayClamped = clamp(lastYear, lastMonth, day);\n const lastDayClamped = clamp(currentYear, currentMonth, Math.max(1, day - 1));\n return {\n firstDay: new Date(lastYear, lastMonth, firstDayClamped),\n lastDay: new Date(currentYear, currentMonth, lastDayClamped),\n };\n};\n","/**\n * Year extraction utilities for datetime operations\n * Provides functions for getting current year information\n */\n\n/**\n * Utility function to get the current year as a number\n * Provides a simple way to retrieve the current year from the system date.\n * Commonly used for copyright notices, date ranges, and year-based filtering.\n *\n * @returns The current year as a four-digit number (e.g., 2025)\n *\n * @example\n * ```ts\n * import { getCurrentYear } from '@/utils/functions';\n *\n * // Get the current year\n * const year = getCurrentYear();\n * // Returns: 2025 (if the current year is 2025)\n *\n * // Usage in a copyright footer\n * const Footer = () => (\n * <footer>\n * &copy; {getCurrentYear()} My Company. All rights reserved.\n * </footer>\n * );\n *\n * // Usage in date ranges\n * const yearRange = `2020-${getCurrentYear()}`;\n * // Returns: \"2020-2025\"\n *\n * // Usage in form validation\n * const isValidYear = (inputYear: number) => {\n * const currentYear = getCurrentYear();\n * return inputYear >= 1900 && inputYear <= currentYear;\n * };\n *\n * // Usage in analytics\n * const currentYearData = analytics.filter(item =>\n * item.year === getCurrentYear()\n * );\n * ```\n */\nexport function getCurrentYear(): number {\n return new Date().getFullYear();\n}\n","/**\n * Utility function for displaying relative time in a human-readable format\n * Provides context-aware time formatting based on elapsed time\n */\n\nimport ms from \"ms\";\n\n/**\n * Formats a timestamp into a human-readable relative time string\n *\n * @param timestamp - The date to format (can be Date object or null)\n * @param options - Formatting options\n * @param options.withAgo - Whether to append \"ago\" to the relative time (default: false)\n * @param options.neverText - Text to display for null timestamps (default: \"Never\")\n * @param options.justNowText - Text to display for timestamps less than 1 second ago (default: \"Just now\")\n * @param options.agoText - Text to append for relative times when withAgo is true (default: \"ago\")\n * @param locale - Optional locale string for date formatting (defaults to 'en-US')\n * @returns A formatted relative time string\n *\n * @example\n * ```ts\n * // For recent timestamps (less than 1 second ago)\n * timeAgo(new Date())\n * // Returns \"Just now\"\n *\n * // For timestamps within the last 23 hours\n * timeAgo(new Date(Date.now() - 1000 * 60 * 30))\n * // Returns \"30m\" (30 minutes)\n *\n * // With \"ago\" suffix\n * timeAgo(new Date(Date.now() - 1000 * 60 * 30), { withAgo: true })\n * // Returns \"30m ago\"\n *\n * // For older timestamps (more than 23 hours)\n * timeAgo(new Date(Date.now() - 1000 * 60 * 60 * 24 * 2))\n * // Returns \"Jun 15\" (date format)\n *\n * // For timestamps in previous years\n * timeAgo(new Date('2022-06-15'))\n * // Returns \"Jun 15, 2022\"\n *\n * // With custom locale\n * timeAgo(new Date('2022-06-15'), {}, 'fr-FR')\n * // Returns \"15 juin 2022\"\n *\n * // For null timestamp\n * timeAgo(null)\n * // Returns \"Never\"\n *\n * // With custom text for internationalization\n * timeAgo(null, { neverText: \"Nunca\" })\n * // Returns \"Nunca\"\n *\n * timeAgo(new Date(), { justNowText: \"Ahora mismo\" })\n * // Returns \"Ahora mismo\"\n *\n * timeAgo(new Date(Date.now() - 1000 * 60 * 30), { withAgo: true, agoText: \"atrás\" })\n * // Returns \"30m atrás\"\n *\n * // Full internationalization example\n * timeAgo(new Date(Date.now() - 1000 * 60 * 5), {\n * withAgo: true,\n * justNowText: \"Baru saja\",\n * agoText: \"yang lalu\",\n * neverText: \"Tidak pernah\"\n * }, 'id-ID')\n * // Returns \"5m yang lalu\"\n * ```\n */\nexport const timeAgo = (\n timestamp: Date | null,\n {\n withAgo,\n neverText = \"Never\",\n justNowText = \"Just now\",\n agoText = \"ago\",\n }: {\n withAgo?: boolean;\n neverText?: string;\n justNowText?: string;\n agoText?: string;\n } = {},\n locale: string = \"en-US\",\n): string => {\n if (!timestamp) return neverText;\n const diff = Date.now() - new Date(timestamp).getTime();\n if (diff < 1000) {\n // Less than 1 second in the past, OR a future timestamp within 1s (clock\n // skew) — treat both as \"just now\" so callers don't render \"-5s\" strings.\n return justNowText;\n } else if (diff > 82800000) {\n // more than 23 hours – similar to how Twitter displays timestamps\n return new Date(timestamp).toLocaleDateString(locale, {\n month: \"short\",\n day: \"numeric\",\n year: new Date(timestamp).getFullYear() !== new Date().getFullYear() ? \"numeric\" : undefined,\n });\n }\n return `${ms(diff)}${withAgo ? ` ${agoText}` : \"\"}`;\n};\n","/**\n * Timezone utilities for datetime operations\n * Provides functions for working with timezones and timezone data\n */\n\n/**\n * Retrieves a list of supported time zones with their labels and values\n * This function fetches the available time zones from the environment,\n * formats their offsets (e.g., \"GMT+2\"), and returns them in a sorted array.\n * Useful for timezone selection dropdowns and user preferences.\n *\n * @returns An array of time zone objects with label and value properties, sorted by offset\n *\n * @example\n * ```ts\n * import { getTimeZones } from '@/utils/functions';\n *\n * // Get all available timezones\n * const timezones = getTimeZones();\n * // Returns: [\n * // { label: \"(GMT-12) Etc/GMT+12\", value: \"Etc/GMT+12\" },\n * // { label: \"(GMT-11) Pacific/Midway\", value: \"Pacific/Midway\" },\n * // { label: \"(GMT+0) Europe/London\", value: \"Europe/London\" },\n * // { label: \"(GMT+1) Europe/Paris\", value: \"Europe/Paris\" },\n * // ...\n * // ]\n *\n * // Use in a select dropdown\n * const TimezoneSelect = () => (\n * <select>\n * {getTimeZones().map(tz => (\n * <option key={tz.value} value={tz.value}>\n * {tz.label}\n * </option>\n * ))}\n * </select>\n * );\n *\n * // Find specific timezone\n * const userTimezone = getTimeZones().find(tz =>\n * tz.value === 'America/New_York'\n * );\n * ```\n */\nexport const getTimeZones = (): { label: string; value: string; numericOffset: number }[] => {\n // `Intl.supportedValuesOf` is unavailable on older engines (e.g. Node <18.14,\n // older Safari). Fall back to a small common list so the helper never throws.\n const safeSupported = (): string[] => {\n if (typeof Intl !== \"undefined\" && typeof Intl.supportedValuesOf === \"function\") {\n try {\n return Intl.supportedValuesOf(\"timeZone\");\n } catch {\n // ignore — fall through\n }\n }\n return [\n \"UTC\",\n \"America/New_York\",\n \"America/Los_Angeles\",\n \"Europe/London\",\n \"Europe/Paris\",\n \"Asia/Tokyo\",\n ];\n };\n\n const timezones = safeSupported();\n\n // Parse a \"GMT[+|-]h(:mm)?\" offset into a numeric value (minutes-from-UTC)\n // so half/quarter-hour zones (e.g. +5:30, +5:45, -3:30) sort correctly.\n // Previously `parseInt(\"5:30\")` returned `5`, tying India with Uzbekistan.\n const parseOffsetMinutes = (offset: string): number => {\n const match = offset.match(/GMT([+-])(\\d{1,2})(?::(\\d{2}))?/);\n if (!match) return 0;\n const sign = match[1] === \"-\" ? -1 : 1;\n const hours = Number.parseInt(match[2] ?? \"0\", 10);\n const minutes = Number.parseInt(match[3] ?? \"0\", 10);\n return sign * (hours * 60 + minutes);\n };\n\n return timezones\n .map((timezone) => {\n const formatter = new Intl.DateTimeFormat(\"en\", {\n timeZone: timezone,\n timeZoneName: \"shortOffset\",\n });\n const parts = formatter.formatToParts(new Date());\n const offset = parts.find((part) => part.type === \"timeZoneName\")?.value || \"\";\n const formattedOffset = offset === \"GMT\" ? \"GMT+0\" : offset;\n\n return {\n value: timezone,\n label: `(${formattedOffset}) ${timezone.replace(/_/g, \" \")}`,\n numericOffset: parseOffsetMinutes(formattedOffset),\n };\n })\n .sort((a, b) => a.numericOffset - b.numericOffset);\n};\n","/**\n * Utility function for formatting file sizes in a human-readable way\n * Converts raw byte values to appropriate size units (KB, MB, GB, etc.)\n */\n\n/**\n * Formats a file size in bytes to a human-readable string with appropriate units\n *\n * @param bytes - File size in bytes\n * @param decimals - Number of decimal places to show (default: 2)\n * @param base - Base for conversion (default: 1024 for binary/IEC, could use 1000 for decimal/SI)\n * @returns A formatted file size string with appropriate unit\n *\n * @example\n * ```ts\n * // Basic usage\n * formatFileSize(1024)\n * // Returns \"1 KB\"\n *\n * // Larger file size\n * formatFileSize(1536)\n * // Returns \"1.5 KB\"\n *\n * // With custom decimal places\n * formatFileSize(1536, 0)\n * // Returns \"2 KB\"\n *\n * // Larger sizes automatically use appropriate units\n * formatFileSize(1048576)\n * // Returns \"1 MB\"\n *\n * // Very large sizes\n * formatFileSize(1073741824)\n * // Returns \"1 GB\"\n *\n * // Using decimal base (1000) instead of binary (1024)\n * formatFileSize(1000000, 2, 1000)\n * // Returns \"1 MB\"\n *\n * // Zero bytes\n * formatFileSize(0)\n * // Returns \"0 Bytes\"\n * ```\n */\nexport function formatFileSize(bytes: number, decimals: number = 2, base: number = 1024): string {\n if (bytes === 0) return \"0 Bytes\";\n if (bytes < 0) return `-${formatFileSize(-bytes, decimals, base)}`;\n\n const k = base;\n const sizes = [\"B\", \"KB\", \"MB\", \"GB\", \"TB\", \"PB\", \"EB\", \"ZB\", \"YB\"];\n const i = Math.min(Math.max(Math.floor(Math.log(bytes) / Math.log(k)), 0), sizes.length - 1);\n\n return `${parseFloat((bytes / k ** i).toFixed(decimals))} ${sizes[i]}`;\n}\n","/**\n * Utility function for resilient network requests\n * Provides fetch implementation with timeout, retry, and exponential backoff\n */\n\n/**\n * Performs a fetch request with automatic retries, timeout, and exponential backoff\n * Handles common error scenarios like rate limiting and server errors\n *\n * @param input - The resource URL or Request object to fetch\n * @param init - Optional fetch initialization options\n * @param options - Configuration options for retry behavior\n * @param options.timeout - Maximum time in ms to wait for a response (default: 5000)\n * @param options.maxRetries - Maximum number of retry attempts (default: 10)\n * @param options.retryDelay - Base delay in ms between retries (default: 1000)\n * @returns A Promise that resolves to the fetch Response\n * @throws Error if all retry attempts fail\n *\n * @example\n * ```ts\n * import { fetchWithRetry } from '@/utils/functions';\n *\n * // Basic usage\n * try {\n * const response = await fetchWithRetry('https://api.example.com/data');\n * const data = await response.json();\n * console.log(data);\n * } catch (error) {\n * console.error('Failed to fetch data:', error);\n * }\n *\n * // With custom options\n * const response = await fetchWithRetry('https://api.example.com/data',\n * {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ key: 'value' })\n * },\n * {\n * timeout: 10000, // 10 second timeout\n * maxRetries: 5, // Try 5 times maximum\n * retryDelay: 500 // Start with 500ms delay\n * }\n * );\n *\n * // Handles rate limiting (429) and server errors (5xx) with exponential backoff\n * // Throws error immediately for authentication failures (403)\n * ```\n */\nexport async function fetchWithRetry(\n input: RequestInfo | URL,\n init?: RequestInit | undefined,\n options: {\n timeout?: number;\n maxRetries?: number;\n retryDelay?: number;\n } = {},\n): Promise<Response> {\n const { timeout = 5000, maxRetries = 10, retryDelay = 1000 } = options;\n\n let lastError: Error | null = null;\n let httpError: Error | null = null;\n\n let lastStatus = 0;\n for (let i = 0; i < maxRetries; i++) {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n }, timeout);\n\n try {\n const response = await fetch(input, {\n ...init,\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (response.ok) {\n return response;\n }\n\n lastStatus = response.status;\n\n // Handle rate limiting and server errors (retryable)\n if (response.status === 429 || response.status >= 500) {\n httpError = new Error(`HTTP error ${response.status}`);\n const delay = retryDelay + i ** 2 * 50;\n await new Promise((resolve) => setTimeout(resolve, delay));\n continue;\n }\n\n // Handle unauthorized errors (non-retryable). Both 401 and 403 typically\n // indicate auth problems that retrying won't fix; surface immediately.\n if (response.status === 401 || response.status === 403) {\n httpError = new Error(response.status === 401 ? \"Unauthorized\" : \"Forbidden\");\n break;\n }\n\n // Handle other HTTP errors (non-retryable)\n let errorMessage: string;\n try {\n const error = await response.json();\n errorMessage = error?.error || `HTTP error ${response.status}`;\n } catch {\n errorMessage = `HTTP error ${response.status}`;\n }\n httpError = new Error(errorMessage);\n break;\n } catch (error) {\n clearTimeout(timeoutId);\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // If this is the last retry, throw the error\n if (i === maxRetries - 1) {\n throw new Error(`Failed after ${maxRetries} retries. Last error: ${lastError.message}`);\n }\n\n // For network errors or timeouts, wait and retry\n const delay = retryDelay + i ** 2 * 50;\n await new Promise((resolve) => setTimeout(resolve, delay));\n }\n }\n\n // Non-retryable HTTP error from inside the loop\n if (httpError) {\n throw httpError;\n }\n\n // This should never be reached due to the throw in the last retry,\n // but TypeScript needs it for type safety. Surface last seen status.\n throw new Error(\n `Failed after ${maxRetries} retries${lastStatus ? ` (last status: ${lastStatus})` : \"\"}`,\n );\n}\n","/**\n * Utility function for fetch requests with timeout capability\n * Provides a way to abort fetch requests that take too long to complete\n */\n\n/**\n * Performs a fetch request with a specified timeout\n * Automatically aborts the request if it exceeds the timeout duration\n *\n * @param input - The resource URL or Request object to fetch\n * @param init - Optional fetch initialization options\n * @param timeout - Maximum time in ms to wait for a response (default: 5000)\n * @returns A Promise that resolves to the fetch Response or rejects on timeout\n * @throws Error if the request times out or fails\n *\n * @example\n * ```ts\n * import { fetchWithTimeout } from '@/utils/functions';\n *\n * // Basic usage with default timeout (5 seconds)\n * try {\n * const response = await fetchWithTimeout('https://api.example.com/data');\n * const data = await response.json();\n * console.log(data);\n * } catch (error) {\n * console.error('Request failed or timed out:', error);\n * }\n *\n * // With custom timeout (2 seconds)\n * const response = await fetchWithTimeout(\n * 'https://api.example.com/data',\n * {\n * method: 'POST',\n * headers: { 'Content-Type': 'application/json' },\n * body: JSON.stringify({ key: 'value' })\n * },\n * 2000\n * );\n *\n * // Will throw an error after 2 seconds if the request hasn't completed\n * ```\n */\nexport function fetchWithTimeout(\n input: RequestInfo | URL,\n init?: RequestInit | undefined,\n timeout: number = 5000,\n): Promise<Response> {\n return new Promise<Response>((resolve, reject) => {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => {\n controller.abort();\n reject(new Error(\"Request timed out\"));\n }, timeout);\n fetch(input, { ...init, signal: controller.signal })\n .then((response) => {\n clearTimeout(timeoutId);\n resolve(response);\n })\n .catch((error) => {\n clearTimeout(timeoutId);\n reject(error);\n });\n });\n}\n","/**\n * Utility functions for data fetching\n * Provides enhanced fetch implementation with error handling for SWR\n */\n\nimport { isDevelopment } from \"../../constants/development\";\nimport { logger } from \"../logging/logger\";\n\n/**\n * Extended Error interface for SWR compatibility\n * Includes additional properties for error information and HTTP status\n */\ninterface SWRError extends Error {\n info: string | Record<string, unknown>;\n status: number;\n}\n\n/**\n * HTTP request methods supported by the `request` utility\n * Ensures type-safe method selection for fetch operations\n */\ntype RequestMethod = \"GET\" | \"POST\" | \"PUT\" | \"DELETE\" | \"PATCH\";\n\n/**\n * Options for the `request` utility\n * Controls request headers and optional logging\n */\ntype RequestOptions = {\n /**\n * Custom headers to include in the request\n * When sending JSON, `Content-Type: application/json` is automatically added\n */\n headers?: Record<string, string>;\n /**\n * Whether to log the endpoint and response to console\n * Useful for debugging during development (default: false)\n */\n log?: boolean;\n};\n\n/**\n * Fetches data from an API endpoint with proper error handling\n * Designed to work seamlessly with SWR data fetching library\n *\n * @param input - The resource URL or Request object to fetch\n * @param init - Optional fetch initialization options with typed headers\n * @returns A Promise that resolves to the JSON response data\n * @throws SWRError with status code and error information on failure\n *\n * @example\n * ```ts\n * import { fetcher } from '@/utils/functions';\n * import useSWR from 'swr';\n *\n * // Basic usage with SWR\n * const { data, error } = useSWR('/api/user', fetcher);\n *\n * // With custom headers\n * const { data } = useSWR('/api/protected', url =>\n * fetcherSWR(url, {\n * headers: {\n * Authorization: `Bearer ${token}`\n * }\n * })\n * );\n *\n * // Direct usage without SWR\n * try {\n * const data = await fetcherSWR('/api/data');\n * console.log(data);\n * } catch (error) {\n * // Error will include status code and error info\n * console.error(`Error ${error.status}: ${error.info}`);\n * }\n * ```\n */\nexport async function fetcherSWR<T>(\n input: RequestInfo,\n init?: RequestInit & { headers?: Record<string, string> },\n): Promise<T> {\n const res = await fetch(input, {\n ...init,\n ...(init?.headers && { headers: init.headers }),\n });\n\n const data = await res.json();\n\n if (!res.ok) {\n const message = data?.error?.message || \"An error occurred while fetching the data.\";\n const error = new Error(message) as SWRError;\n error.info = message;\n error.status = res.status;\n\n throw error;\n }\n\n return data;\n}\n\n/**\n * Performs an HTTP request with optional JSON or FormData payload\n * Automatically sets `Content-Type: application/json` for JSON bodies\n * Supports basic logging of endpoint and response data\n *\n * @param endpoint - The target URL to send the request to\n * @param method - HTTP method to use (default: `GET`)\n * @param body - Request payload; accepts plain objects or `FormData`\n * @param options - Additional request options like headers and logging\n * @returns A Promise resolving to parsed JSON response\n *\n * @example\n * ```ts\n * // GET request\n * const users = await fetcher('/api/users');\n *\n * // POST JSON body\n * const created = await fetcher('/api/users', 'POST', { name: 'Alice' });\n *\n * // PUT with custom header\n * const updated = await fetcher('/api/users/1', 'PUT', { name: 'Bob' }, {\n * headers: { Authorization: `Bearer ${token}` },\n * });\n *\n * // Multipart/FormData upload\n * const form = new FormData();\n * form.append('file', file);\n * const upload = await fetcher('/api/upload', 'POST', form);\n * ```\n */\nexport async function fetcher<T>(\n endpoint: string,\n method: RequestMethod = \"GET\",\n body?: unknown,\n options?: RequestOptions,\n): Promise<T> {\n const isFormData = typeof FormData !== \"undefined\" && body instanceof FormData;\n\n const headers: Record<string, string> = {\n ...options?.headers,\n };\n\n let payload: BodyInit | undefined;\n\n if (body !== undefined) {\n if (isFormData) {\n payload = body as FormData;\n } else {\n if (!headers[\"Content-Type\"]) {\n headers[\"Content-Type\"] = \"application/json\";\n }\n payload = JSON.stringify(body);\n }\n }\n\n const res = await fetch(endpoint, {\n method,\n headers,\n body: payload,\n });\n\n // Parse the JSON body defensively — non-JSON responses (HTML error pages,\n // empty 204 bodies) would otherwise throw an opaque SyntaxError.\n let data: unknown;\n try {\n data = await res.json();\n } catch {\n data = undefined;\n }\n\n if (options?.log && isDevelopment) {\n logger.info(`[request] ${endpoint}`, data);\n }\n\n // Treat non-2xx as an error instead of returning `undefined` as data —\n // matches the behavior of `fetcherSWR` and surfaces failures to callers.\n if (!res.ok) {\n const message =\n (typeof data === \"object\" && data !== null && \"error\" in data\n ? String((data as Record<string, unknown>).error)\n : `HTTP error ${res.status}`) || `HTTP error ${res.status}`;\n const error = new Error(message) as Error & { status: number };\n error.status = res.status;\n throw error;\n }\n\n // Unwrap `{ data: ... }` envelopes when present, otherwise return the body as-is.\n return typeof data === \"object\" && data !== null && \"data\" in data\n ? (data as { data: T }).data\n : (data as T);\n}\n","/**\n * API utilities for Next.js applications\n * Provides helper functions for handling API requests, extracting client information,\n * and managing request/response data in Next.js API routes and middleware\n */\n\nimport { logger } from \"../logging/logger\";\n\n/**\n * Extracts the client IP address from a Next.js request with comprehensive fallback logic\n *\n * This function attempts to get the real client IP address by checking multiple headers\n * in order of preference. It handles various proxy configurations and CDN setups.\n *\n * Header priority:\n * 1. x-forwarded-for (most common, supports proxy chains)\n * 2. x-real-ip (nginx proxy)\n * 3. x-client-ip (Apache proxy)\n * 4. cf-connecting-ip (Cloudflare)\n * 5. x-cluster-client-ip (cluster environments)\n * 6. forwarded (RFC 7239 standard)\n * 7. request.ip (Next.js fallback)\n *\n * @param request - The Next.js request object\n * @returns The client IP address string, or 'unknown' if not found\n *\n * @example\n * ```typescript\n * // In a Next.js API route\n * import { NextRequest, NextResponse } from 'next/server';\n * import { getClientIP } from '@/lib/api';\n *\n * export async function GET(request: NextRequest) {\n * const clientIP = getClientIP(request);\n * console.log(`Request from IP: ${clientIP}`);\n *\n * return NextResponse.json({\n * message: 'Success',\n * clientIP\n * });\n * }\n *\n * // In middleware\n * import { NextRequest, NextResponse } from 'next/server';\n * import { getClientIP } from '@/lib/api';\n *\n * export function middleware(request: NextRequest) {\n * const clientIP = getClientIP(request);\n *\n * // Log or rate limit based on IP\n * console.log(`Middleware: Request from ${clientIP}`);\n *\n * return NextResponse.next();\n * }\n * ```\n */\nexport function getClientIP(request: {\n headers: { get(name: string): string | null };\n ip?: string;\n}): string {\n // Try x-forwarded-for first (most common, handles proxy chains)\n const xForwardedFor = request.headers.get(\"x-forwarded-for\");\n if (xForwardedFor) {\n // x-forwarded-for can contain multiple IPs, take the first one (original client)\n const ips = xForwardedFor.split(\",\").map((ip) => ip.trim());\n const clientIP = ips[0];\n if (clientIP && clientIP !== \"unknown\") {\n return clientIP;\n }\n }\n\n // Try other common headers\n const headers = [\n \"x-real-ip\", // Nginx proxy\n \"x-client-ip\", // Apache proxy\n \"cf-connecting-ip\", // Cloudflare\n \"x-cluster-client-ip\", // Cluster environments\n ];\n\n for (const header of headers) {\n const ip = request.headers.get(header);\n if (ip && ip !== \"unknown\" && ip.trim() !== \"\") {\n return ip.trim();\n }\n }\n\n // Try RFC 7239 Forwarded header\n const forwarded = request.headers.get(\"forwarded\");\n if (forwarded) {\n const forMatch = forwarded.match(/for=([^;,\\s]+)/i);\n if (forMatch?.[1]) {\n // Remove quotes and brackets if present\n const ip = forMatch[1].replace(/[\"[\\]]/g, \"\");\n if (ip && ip !== \"unknown\") {\n return ip;\n }\n }\n }\n\n // Try Next.js request.ip as fallback\n const requestIP = request.ip;\n if (requestIP && requestIP !== \"unknown\") {\n return requestIP;\n }\n\n // Final fallback\n return \"unknown\";\n}\n\n/**\n * Validates if a string is a valid IP address (IPv4 or IPv6)\n *\n * @param ip - The IP address string to validate\n * @returns True if the IP is valid, false otherwise\n *\n * @example\n * ```typescript\n * const ip = getClientIP(request);\n * if (isValidIP(ip)) {\n * console.log('Valid IP:', ip);\n * } else {\n * console.log('Invalid or unknown IP');\n * }\n * ```\n */\nexport function isValidIP(ip: string): boolean {\n if (!ip || ip === \"unknown\") return false;\n\n // IPv4 regex\n const ipv4Regex =\n /^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;\n\n // IPv6 regex (supports full, compressed \"::\", and IPv4-mapped forms)\n const ipv6Regex =\n /^(?:(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?::[0-9a-fA-F]{1,4}){1,6}|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|::(?:ffff(?::0{1,4})?:)?(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)|(?:[0-9a-fA-F]{1,4}:){1,4}:(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))$/;\n\n return ipv4Regex.test(ip) || ipv6Regex.test(ip);\n}\n\n/**\n * Gets user agent information from the request\n *\n * @param request - The Next.js request object\n * @returns User agent string or 'unknown' if not found\n *\n * @example\n * ```typescript\n * const userAgent = getUserAgent(request);\n * console.log('User Agent:', userAgent);\n * ```\n */\nexport function getUserAgent(request: { headers: { get(name: string): string | null } }): string {\n return request.headers.get(\"user-agent\") || \"unknown\";\n}\n\n/**\n * Gets the request origin/referer information\n *\n * @param request - The Next.js request object\n * @returns Origin information object\n *\n * @example\n * ```typescript\n * const origin = getRequestOrigin(request);\n * console.log('Origin:', origin.origin);\n * console.log('Referer:', origin.referer);\n * ```\n */\nexport function getRequestOrigin(request: { headers: { get(name: string): string | null } }): {\n origin: string;\n referer: string;\n host: string;\n} {\n return {\n origin: request.headers.get(\"origin\") || \"unknown\",\n referer: request.headers.get(\"referer\") || \"unknown\",\n host: request.headers.get(\"host\") || \"unknown\",\n };\n}\n\n/**\n * Extracts the client IP address from a generic headers object (Node.js, Express, etc)\n *\n * This function is similar to getClientIP, but works with any headers object.\n *\n * @param headers - An object containing HTTP headers (key: string, value: string | string[] | undefined)\n * @returns The client IP address string, or 'unknown' if not found\n *\n * @example\n * ```typescript\n * // In Express.js\n * app.use((req, res, next) => {\n * const clientIP = getClientIPFromHeaders(req.headers);\n * console.log('Request from IP:', clientIP);\n * next();\n * });\n * ```\n */\nexport function getClientIPFromHeaders(\n headers: Record<string, string | string[] | undefined>,\n): string {\n // Helper to get header value (case-insensitive)\n const getHeader = (name: string): string | undefined => {\n const value = headers[name] ?? headers[name.toLowerCase()];\n if (Array.isArray(value)) return value[0];\n return value;\n };\n\n // Try x-forwarded-for first (most common, handles proxy chains)\n const xForwardedFor = getHeader(\"x-forwarded-for\");\n if (xForwardedFor) {\n const ips = xForwardedFor.split(\",\").map((ip) => ip.trim());\n const clientIP = ips[0];\n if (clientIP && clientIP !== \"unknown\") {\n return clientIP;\n }\n }\n\n // Try other common headers\n const headerNames = [\"x-real-ip\", \"x-client-ip\", \"cf-connecting-ip\", \"x-cluster-client-ip\"];\n for (const header of headerNames) {\n const ip = getHeader(header);\n if (ip && ip !== \"unknown\" && ip.trim() !== \"\") {\n return ip.trim();\n }\n }\n\n // Try RFC 7239 Forwarded header\n const forwarded = getHeader(\"forwarded\");\n if (forwarded) {\n const forMatch = forwarded.match(/for=([^;,\"]+)/i);\n if (forMatch?.[1]) {\n const ipClean = forMatch[1].replace(/[\"[\\]]/g, \"\");\n if (ipClean && ipClean !== \"unknown\") {\n return ipClean;\n }\n }\n }\n\n // Final fallback\n return \"unknown\";\n}\n\n/**\n * Gets user agent information from a generic headers object (Node.js, Express, etc)\n *\n * @param headers - An object containing HTTP headers (key: string, value: string | string[] | undefined)\n * @returns User agent string or 'unknown' if not found\n *\n * @example\n * ```typescript\n * // In Express.js\n * app.use((req, res, next) => {\n * const userAgent = getUserAgentFromHeaders(req.headers);\n * console.log('User Agent:', userAgent);\n * next();\n * });\n * ```\n */\nexport function getUserAgentFromHeaders(\n headers: Record<string, string | string[] | undefined>,\n): string {\n const value = headers[\"user-agent\"] ?? headers[\"User-Agent\"];\n if (Array.isArray(value)) return value[0] || \"unknown\";\n return value || \"unknown\";\n}\n\n/**\n * Get the client's public IP address using external services.\n *\n * This utility is intended for client-side usage only (it checks for `window`).\n * It attempts multiple providers for resiliency and normalizes the response\n * to a simple string. If all providers fail or the environment is not a\n * browser, it resolves to `'unknown'`.\n *\n * Providers queried (in order):\n * - `https://api.ipify.org?format=json`\n * - `https://ipapi.co/json/`\n * - `https://api.ip.sb/jsonip`\n *\n * @returns Promise that resolves to an IP address string or `'unknown'` if not available\n *\n * @example\n * ```ts\n * import { getIPAddress } from \"@kumix/ui/utils/ip\";\n *\n * const ip = await getIPAddress();\n * // e.g., \"203.0.113.42\" or \"unknown\"\n *\n * // Example in a React component\n * // useEffect(() => {\n * // getIPAddress().then(setIp);\n * // }, []);\n * ```\n */\nexport async function getIPAddress(): Promise<string> {\n if (typeof window === \"undefined\") {\n return \"unknown\";\n }\n\n try {\n // Try multiple IP detection services for reliability\n const services = [\n \"https://api.ipify.org?format=json\",\n \"https://ipapi.co/json/\",\n \"https://api.ip.sb/jsonip\",\n ];\n\n for (const service of services) {\n try {\n const response = await fetch(service, {\n method: \"GET\",\n headers: {\n Accept: \"application/json\",\n },\n });\n\n if (response.ok) {\n const data = await response.json();\n // Different services return IP in different fields\n const ip = data.ip || data.query || data.ipAddress;\n if (ip && typeof ip === \"string\") {\n return ip;\n }\n }\n } catch (serviceError) {\n // Continue to next service if this one fails\n logger.warn(`IP service ${service} failed:`, serviceError);\n }\n }\n\n return \"unknown\";\n } catch (error) {\n console.error(\"Failed to get client IP:\", error);\n return \"unknown\";\n }\n}\n","/**\n * Normalize a pathname string.\n *\n * - Ensures it always starts with '/'\n * - Collapses multiple slashes (e.g., `'//a///b'` becomes `'/a/b'`)\n * - Removes trailing slash except for root path (e.g., `'/login/'` becomes `'/login'`)\n *\n * @param input - Any path-like string\n * @returns A normalized path beginning with '/'\n *\n * @example\n * ```ts\n * import { normalizePath } from \"@kumix/ui/utils/parse\";\n *\n * normalizePath(\"dashboard\"); // \"/dashboard\"\n * normalizePath(\"//a///b\"); // \"/a/b\"\n * normalizePath(\"/login/\"); // \"/login\"\n * normalizePath(\"\"); // \"/\"\n * ```\n */\nexport function normalizePath(input: string): string {\n if (!input) return \"/\";\n let p = input.trim();\n if (!p.startsWith(\"/\")) p = `/${p}`;\n p = p.replace(/\\/{2,}/g, \"/\");\n if (p.length > 1 && p.endsWith(\"/\")) p = p.slice(0, -1);\n return p;\n}\n\n/**\n * Interface for parsed request data\n */\nexport interface ParsedRequest {\n /** Normalized domain name (lowercase, without www) */\n domain: string;\n /** URL pathname (e.g., '/dashboard/users') */\n path: string;\n /** Full path including query parameters (e.g., '/dashboard/users?page=1') */\n fullPath: string;\n /** First path segment (e.g., 'dashboard' from '/dashboard/users') */\n key: string;\n /** Full path without leading slash (e.g., 'dashboard/users') */\n fullKey: string;\n /** Query parameters as object */\n searchParamsObj: Record<string, string>;\n /** Query parameters as string (e.g., '?page=1&limit=10') */\n searchParamsString: string;\n}\n\n/**\n * Parse and normalize a Next.js `NextRequest`.\n *\n * Extracts domain, normalized path, first segment key, full path, and\n * query parameters (both as object and as string). Handles international\n * characters via `decodeURIComponent` and normalizes the host by removing\n * a leading `www.`.\n *\n * @param req - The incoming Next.js `NextRequest`\n * @returns Parsed request data with normalized components\n *\n * @example\n * ```ts\n * import type { NextRequest } from \"next/server\";\n * import { parse } from \"@kumix/ui/utils/parse\";\n *\n * export function middleware(req: NextRequest) {\n * const { domain, path, fullPath, key } = parse(req);\n *\n * console.log(domain); // e.g., \"api.kumix.io\"\n * console.log(path); // e.g., \"/v1/users\"\n * console.log(fullPath); // e.g., \"/v1/users?page=1\"\n * console.log(key); // e.g., \"v1\"\n * }\n * ```\n *\n * @example\n * ```ts\n * // Handling international URLs\n * const { key, fullKey } = parse(req);\n * console.log(key); // Decoded first path segment\n * console.log(fullKey); // Decoded full path\n * ```\n *\n * @example\n * ```ts\n * // Working with query parameters\n * const { searchParamsObj, searchParamsString } = parse(req);\n * // searchParamsObj -> { page: \"1\", limit: \"10\" }\n * // searchParamsString -> \"?page=1&limit=10\"\n * ```\n */\nexport const parse =\n // biome-ignore lint/suspicious/noExplicitAny: disable\n (req: any): ParsedRequest => {\n // Extract and normalize domain\n const rawHost = req.headers.get(\"host\");\n const domain = (rawHost || \"\").replace(/^www\\./, \"\").toLowerCase();\n\n // Extract pathname from URL (e.g., kumix.io/stats/github -> /stats/github)\n const path = req.nextUrl.pathname;\n\n // Extract and process search parameters\n const searchParams = req.nextUrl.searchParams.toString();\n const searchParamsObj = Object.fromEntries(req.nextUrl.searchParams);\n const searchParamsString = searchParams.length > 0 ? `?${searchParams}` : \"\";\n\n // Construct full path including query parameters\n const fullPath = `${path}${searchParamsString}`;\n\n // Extract path components with proper URL decoding.\n // This handles international characters (Hebrew, Arabic, Chinese, etc.).\n // `decodeURIComponent` throws URIError on malformed sequences (e.g. stray\n // `%`); fall back to the raw segment so a bad URL never crashes the request.\n const safeDecode = (value: string): string => {\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n };\n const pathSegments = path.split(\"/\").filter(Boolean);\n const key = pathSegments.length > 0 ? safeDecode(pathSegments[0]) : \"\";\n const fullKey = path.length > 1 ? safeDecode(path.slice(1)) : \"\";\n\n return {\n domain,\n path,\n fullPath,\n key,\n fullKey,\n searchParamsObj,\n searchParamsString,\n };\n };\n","/**\n * Google reCAPTCHA server-side verification utilities\n * Provides secure token verification for reCAPTCHA v2 and v3\n * Integrates with Google's verification API for bot protection\n */\n\nimport { RECAPTCHA_SECRET_KEY } from \"../../constants/env\";\nimport { logger } from \"../logging/logger\";\n\n/**\n * Response interface from Google reCAPTCHA verification API\n * Defines the structure of the response from Google's verification endpoint\n *\n * @property success - Whether the verification was successful\n * @property challenge_ts - Timestamp of the challenge (ISO format)\n * @property hostname - Hostname of the site where the challenge was solved\n * @property error-codes - Array of error codes if verification failed\n */\ninterface ReCaptchaVerifyResponse {\n success: boolean;\n challenge_ts?: string;\n hostname?: string;\n \"error-codes\"?: string[];\n}\n\n/**\n * Verifies a reCAPTCHA token with Google's verification API\n *\n * This function sends the token and secret key to Google's reCAPTCHA\n * verification endpoint and returns whether the verification was successful.\n *\n * @param token - The reCAPTCHA token from the client-side\n * @returns Promise resolving to a boolean indicating verification success\n *\n * @example\n * ```typescript\n * // In a server action or API route\n * const isValid = await verifyRecaptchaToken(token);\n *\n * if (!isValid) {\n * throw new Error('reCAPTCHA verification failed');\n * }\n * ```\n */\nexport async function verifyRecaptchaToken(token: string): Promise<boolean> {\n try {\n const secretKey = RECAPTCHA_SECRET_KEY;\n\n if (!secretKey) {\n logger.error(\"RECAPTCHA_SECRET_KEY is not set\");\n return false;\n }\n\n const response = await fetch(\"https://www.google.com/recaptcha/api/siteverify\", {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/x-www-form-urlencoded\",\n },\n body: `secret=${encodeURIComponent(secretKey)}&response=${encodeURIComponent(token)}`,\n });\n\n const data: ReCaptchaVerifyResponse = await response.json();\n\n if (!data.success) {\n logger.error(\"reCAPTCHA verification failed:\", data[\"error-codes\"]);\n return false;\n }\n\n return true;\n } catch (error) {\n logger.error(\"Error verifying reCAPTCHA token:\", error);\n return false;\n }\n}\n","/**\n * Utility functions for logging\n * Provides structured logging to Slack channels based on message type\n */\n\nimport { isDevelopment } from \"../../constants/development\";\nimport { SLACK_WEBHOOKS } from \"../../constants/env\";\nimport { logger } from \"./logger\";\n\n/**\n * Mapping of log types to their corresponding Slack webhook environment variables\n * Each log type is sent to a different Slack channel\n */\nconst logTypeToEnv = {\n alerts: SLACK_WEBHOOKS.ALERTS,\n cron: SLACK_WEBHOOKS.CRON,\n links: SLACK_WEBHOOKS.LINKS,\n subscribers: SLACK_WEBHOOKS.SUBSCRIBERS,\n errors: SLACK_WEBHOOKS.ERRORS,\n};\n\n/**\n * Logs a message to Slack and/or console\n * Sends structured messages to different Slack channels based on message type\n *\n * @param options - Logging options\n * @param options.message - The message to log\n * @param options.type - The type of log determining which Slack channel to use\n * @param options.mention - Whether to mention a specific user in Slack (default: false)\n * @returns A Promise that resolves to the fetch response or undefined\n *\n * @example\n * ```ts\n * import { log } from '@/utils/functions';\n *\n * // Log an error\n * await log({\n * message: \"Database connection failed\",\n * type: \"errors\"\n * });\n *\n * // Log with a mention\n * await log({\n * message: \"Critical system failure\",\n * type: \"alerts\",\n * mention: true\n * });\n *\n * // Log subscriber activity\n * await log({\n * message: \"New subscriber: user@example.com\",\n * type: \"subscribers\"\n * });\n *\n * // In development, logs to console instead of Slack\n * ```\n */\nexport const SlackLog = async ({\n message,\n type,\n mention = false,\n mentionUserId,\n}: {\n message: string;\n type: \"alerts\" | \"cron\" | \"links\" | \"subscribers\" | \"errors\";\n /**\n * Mention a Slack user when `true`. Requires `mentionUserId` to be provided\n * (defaults to env `SLACK_MENTION_USER_ID`) — previously a hardcoded user ID\n * was baked into this published package.\n */\n mention?: boolean;\n /** Slack user ID (e.g. `U0404G6J3NJ`) to mention. Falls back to env. */\n mentionUserId?: string;\n}) => {\n const HOOK = logTypeToEnv[type];\n\n // In development or when the relevant webhook is missing, log to console and bail\n if (isDevelopment || !HOOK) {\n logger.log(message);\n return;\n }\n\n const resolvedMentionId =\n mentionUserId ||\n (typeof process !== \"undefined\" ? process.env.SLACK_MENTION_USER_ID : undefined);\n\n try {\n return await fetch(HOOK, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n },\n body: JSON.stringify({\n blocks: [\n {\n type: \"section\",\n text: {\n type: \"mrkdwn\",\n // prettier-ignore\n text: `${mention && resolvedMentionId ? `<@${resolvedMentionId}> ` : \"\"}${type === \"alerts\" || type === \"errors\" ? \":alert: \" : \"\"}${message}`,\n },\n },\n ],\n }),\n });\n } catch (error) {\n logger.log(`Failed to log to Slack. Error: ${error}`);\n }\n};\n","/**\n * Performance debouncing utilities\n * Provides functions for delaying function execution until after a specified delay\n */\n\n/**\n * Debounces a function to delay its execution until after a specified delay\n * Debouncing delays the execution of a function until after a specified time\n * has passed since the last time it was invoked. This is useful for scenarios\n * like search input where you want to wait for the user to stop typing.\n *\n * @param func - The function to debounce\n * @param wait - The delay in milliseconds\n * @returns A debounced version of the provided function\n *\n * @example\n * ```ts\n * import { debounce } from '@/utils/functions';\n *\n * // Debounce search input\n * const debouncedSearch = debounce((query: string) => {\n * performSearch(query);\n * }, 500);\n *\n * // Use in input handler\n * const handleInputChange = (e: ChangeEvent<HTMLInputElement>) => {\n * debouncedSearch(e.target.value);\n * };\n *\n * // Debounce window resize\n * const debouncedResize = debounce(() => {\n * handleWindowResize();\n * recalculateLayout();\n * }, 250);\n *\n * window.addEventListener('resize', debouncedResize);\n *\n * // Debounce form validation\n * const debouncedValidate = debounce((formData: FormData) => {\n * validateForm(formData);\n * }, 300);\n *\n * // Debounce auto-save\n * const debouncedSave = debounce(() => {\n * saveDocument();\n * }, 2000);\n * ```\n */\nexport function debounce<T extends (...args: never[]) => unknown>(\n func: T,\n wait: number,\n): (...args: Parameters<T>) => void {\n let timeout: ReturnType<typeof setTimeout> | null = null;\n\n return (...args: Parameters<T>): void => {\n if (timeout) {\n clearTimeout(timeout);\n }\n\n timeout = setTimeout(() => {\n func(...args);\n }, wait);\n };\n}\n","/**\n * Performance throttling utilities\n * Provides functions for limiting function execution frequency to improve performance\n */\n\n/**\n * Throttles a function to limit its execution to once every specified duration\n * Throttling ensures that a function is called at most once in a specified time period.\n * This is useful for performance optimization, especially for events that fire frequently\n * like scroll, resize, or mousemove events.\n *\n * @param func - The function to throttle\n * @param limit - The minimum delay in milliseconds between calls\n * @returns A throttled version of the provided function\n *\n * @example\n * ```ts\n * import { throttle } from '@/utils/functions';\n *\n * // Throttle scroll event handler\n * const handleScroll = throttle(() => {\n * console.log('Scroll event fired');\n * updateScrollPosition();\n * }, 100);\n *\n * window.addEventListener('scroll', handleScroll);\n *\n * // Throttle API calls\n * const throttledSearch = throttle((query: string) => {\n * searchAPI(query);\n * }, 300);\n *\n * // Throttle resize handler\n * const handleResize = throttle(() => {\n * console.log('Window resized');\n * recalculateLayout();\n * }, 250);\n *\n * window.addEventListener('resize', handleResize);\n *\n * // Throttle button clicks\n * const throttledSubmit = throttle(() => {\n * submitForm();\n * }, 1000);\n * ```\n */\nexport const throttle = <T extends (...args: never[]) => unknown>(\n func: T,\n limit: number,\n): ((...args: Parameters<T>) => void) => {\n let lastFunc: ReturnType<typeof setTimeout> | null = null;\n let lastRan: number | null = null;\n\n return function (this: unknown, ...args: Parameters<T>) {\n if (lastRan === null) {\n func.apply(this, args);\n lastRan = Date.now();\n } else {\n if (lastFunc !== null) {\n clearTimeout(lastFunc);\n }\n lastFunc = setTimeout(\n () => {\n if (Date.now() - (lastRan as number) >= limit) {\n func.apply(this, args);\n lastRan = Date.now();\n }\n },\n limit - (Date.now() - (lastRan as number)),\n );\n }\n };\n};\n","/**\n * Get avatar size class name\n * @param size - Avatar size ('sm', 'lg', or null/undefined for default)\n * @returns Tailwind CSS class name for avatar size\n */\nexport function getSizeAvatar(size: string | null | undefined) {\n return size === \"sm\" ? \"size-6\" : size === \"lg\" ? \"size-10\" : \"size-8\";\n}\n\n/**\n * Get user name from user object\n * @param user - User object\n * @returns User name\n */\nexport function getUserName(\n // biome-ignore lint/suspicious/noExplicitAny: <>\n user: any | null | undefined,\n) {\n return user?.name || user?.displayUsername || user?.username || user?.email;\n}\n","/**\n * Utility function for string case conversion\n * Provides conversion from various cases (snake, kebab, space, Pascal) to camelCase\n */\n\n/**\n * Converts a string to camelCase.\n * Handles snake_case, kebab-case, CONST_CASE, PascalCase, and space-separated words.\n *\n * @param str - The string to convert to camelCase\n * @returns The camelCase version of the input string\n *\n * @example\n * ```ts\n * toCamelCase('user_name') // \"userName\"\n * toCamelCase('user-name') // \"userName\"\n * toCamelCase('first name') // \"firstName\"\n * toCamelCase('PascalCase') // \"pascalCase\"\n * toCamelCase('first_name_last') // \"firstNameLastName\"\n * ```\n */\nexport const toCamelCase = (str: string): string => {\n if (!str) return \"\";\n // Split on any non-alphanumeric boundary (underscore, dash, space) OR at the\n // transition between lowercase/digit and uppercase (PascalCase boundaries).\n const words = str\n .replace(/([a-z0-9])([A-Z])/g, \"$1 $2\")\n .split(/[^a-zA-Z0-9]+/)\n .filter(Boolean);\n if (words.length === 0) return \"\";\n const [first, ...rest] = words;\n return `${first.toLowerCase()}${rest\n .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())\n .join(\"\")}`;\n};\n","/**\n * Utility function for string capitalization\n * Provides consistent text formatting for display purposes\n */\n\n/**\n * Capitalizes the first character of each word in a string\n * Handles null or undefined values by returning them unchanged\n *\n * @param str - The string to capitalize (can be undefined or null)\n * @returns The capitalized string, or the original value if not a string\n *\n * @example\n * ```ts\n * // Basic usage\n * capitalize('hello world')\n * // Returns \"Hello World\"\n *\n * // Single word\n * capitalize('javascript')\n * // Returns \"Javascript\"\n *\n * // Already capitalized text remains unchanged\n * capitalize('Hello World')\n * // Returns \"Hello World\"\n *\n * // Handles null or undefined\n * capitalize(null)\n * // Returns null\n *\n * capitalize(undefined)\n * // Returns undefined\n *\n * // Mixed case\n * capitalize('javaScript is COOL')\n * // Returns \"Javascript Is COOL\"\n * ```\n */\nexport function capitalize(str?: string | null): string | undefined | null {\n if (!str || typeof str !== \"string\") return str;\n return str\n .split(\" \")\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(\" \");\n}\n","/**\n * Utility functions for CSS class name management\n * Provides optimized class name merging with Tailwind CSS conflict resolution\n * Essential for component styling and conditional class application\n */\n\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\n/**\n * Merges Tailwind class names, resolving any conflicts.\n * This utility combines clsx for conditional classes with tailwind-merge\n * to properly handle Tailwind CSS class conflicts.\n *\n * @param inputs - An array of class names, objects, or arrays to merge\n * @returns A string of merged and optimized class names\n *\n * @example\n * ```tsx\n * // Basic usage\n * <div className={cn(\"px-4 py-2\", \"bg-blue-500\", \"text-white\")}>\n * Button\n * </div>\n *\n * // With conditional classes\n * <div className={cn(\n * \"px-4 py-2\",\n * isActive && \"bg-blue-500\",\n * !isActive && \"bg-gray-200\",\n * isDisabled && \"opacity-50 cursor-not-allowed\"\n * )}>\n * Button\n * </div>\n *\n * // Resolving conflicts (last one wins)\n * <div className={cn(\"px-2\", \"px-4\")}>\n * // Results in \"px-4\", not \"px-2 px-4\"\n * </div>\n * ```\n */\nexport function cn(...inputs: ClassValue[]): string {\n return twMerge(clsx(inputs));\n}\n","/**\n * Utility function for combining words into a grammatically correct list\n * Provides natural language formatting for arrays of words\n */\n\n/**\n * Combines an array of words into a grammatically correct list\n * Joins words with commas and adds \"and\" before the last word\n *\n * @param words - Array of words to combine\n * @returns A string with words combined in a natural language format\n *\n * @example\n * ```ts\n * import { combineWords } from '@/utils/functions';\n *\n * // Basic usage\n * combineWords(['apple', 'banana', 'orange'])\n * // Returns \"apple, banana and orange\"\n *\n * // With two words\n * combineWords(['apple', 'banana'])\n * // Returns \"apple and banana\"\n *\n * // With one word\n * combineWords(['apple'])\n * // Returns \"apple\"\n *\n * // With empty array\n * combineWords([])\n * // Returns \"\"\n * ```\n */\nexport const combineWords = (words: string[]): string => {\n return (\n words\n .join(\", \")\n // final one should be \"and\" instead of comma\n .replace(/, ([^,]*)$/, \" and $1\")\n );\n};\n","/**\n * Utility function for formatting numbers as currency\n * Provides consistent currency formatting with customizable options\n */\n\n/**\n * Formats a number as a currency string using Intl.NumberFormat\n *\n * @param value - The numeric value to format as currency\n * @param options - Optional Intl.NumberFormat options to customize formatting\n * @param locale - Optional locale string (defaults to 'en-US')\n * @param currencyCode - Optional currency code (defaults to 'USD')\n * @returns A formatted currency string\n *\n * @example\n * ```ts\n * // Basic usage with defaults (USD)\n * currencyFormatter(1000)\n * // Returns \"$1,000.00\"\n *\n * // With custom currency\n * currencyFormatter(1000, {}, 'en-US', 'EUR')\n * // Returns \"€1,000.00\"\n *\n * // With custom locale\n * currencyFormatter(1000, {}, 'de-DE', 'EUR')\n * // Returns \"1.000,00 €\"\n *\n * // With custom options (no decimals)\n * currencyFormatter(1234.56, { maximumFractionDigits: 0 })\n * // Returns \"$1,235\"\n *\n * // Combining custom options, locale and currency\n * currencyFormatter(1234.56, { maximumFractionDigits: 0 }, 'ja-JP', 'JPY')\n * // Returns \"¥1,235\"\n * ```\n */\nexport const currencyFormatter = (\n value: number,\n options?: Intl.NumberFormatOptions,\n locale: string = \"en-US\",\n currencyCode: string = \"USD\",\n): string =>\n Intl.NumberFormat(locale, {\n style: \"currency\",\n currency: currencyCode,\n ...options,\n }).format(value);\n","/**\n * String initials extraction utilities\n * Provides functions for extracting initials from names for avatars and displays\n */\n\n/**\n * Extracts initials from a given name with customizable count\n * Takes a full name and extracts the first letter of each word to create initials.\n * Useful for avatar placeholders, user displays, and profile components.\n *\n * @param name - The full name to extract initials from\n * @param count - The number of initials to return (defaults to all initials)\n * @returns A string of initials from the name\n *\n * @example\n * ```ts\n * import { getInitials } from '@/utils/functions';\n *\n * // Basic usage\n * const initials1 = getInitials('John Doe');\n * // Returns: 'JD'\n *\n * const initials2 = getInitials('John Michael Doe');\n * // Returns: 'JMD'\n *\n * // Limit number of initials\n * const initials3 = getInitials('John Michael Doe', 2);\n * // Returns: 'JM'\n *\n * const initials4 = getInitials('John Doe', 1);\n * // Returns: 'J'\n *\n * // Handle edge cases\n * const empty1 = getInitials('');\n * // Returns: ''\n *\n * const empty2 = getInitials(null);\n * // Returns: ''\n *\n * const single = getInitials('John');\n * // Returns: 'J'\n *\n * // Use in avatar component\n * const Avatar = ({ name }: { name: string }) => (\n * <div className=\"avatar\">\n * {getInitials(name, 2)}\n * </div>\n * );\n * ```\n */\nexport const getInitials = (name: string | null | undefined, count?: number): string => {\n if (!name || typeof name !== \"string\") {\n return \"\";\n }\n\n const initials = name\n .split(\" \")\n .filter(Boolean)\n .map((part) => part[0].toUpperCase());\n\n return count && count > 0 ? initials.slice(0, count).join(\"\") : initials.join(\"\");\n};\n","/**\n * Utility function for formatting numbers with abbreviations\n * Provides human-readable number formatting for large values\n */\n\n/**\n * Formats a number with abbreviations (K, M, G, T, etc.) or as a full number\n *\n * @param num - The number to format\n * @param opts - Formatting options\n * @param opts.digits - Number of decimal places to show (default: 1)\n * @param opts.full - Whether to show the full number without abbreviation (default: false)\n * @param locale - Optional locale string for full number formatting (defaults to 'en-US')\n * @returns A formatted number string\n *\n * @example\n * ```ts\n * // Basic usage\n * nFormatter(1500)\n * // Returns \"1.5K\"\n *\n * // With custom decimal places\n * nFormatter(1500, { digits: 2 })\n * // Returns \"1.50K\"\n *\n * // Full number formatting\n * nFormatter(1500, { full: true })\n * // Returns \"1,500\"\n *\n * // Small numbers\n * nFormatter(0.75, { digits: 2 })\n * // Returns \"0.75\"\n *\n * // Large numbers with abbreviations\n * nFormatter(1500000)\n * // Returns \"1.5M\"\n *\n * // With custom locale\n * nFormatter(1500000, { full: true }, 'de-DE')\n * // Returns \"1.500.000\"\n *\n * // Zero or undefined\n * nFormatter(0)\n * // Returns \"0\"\n * nFormatter(undefined)\n * // Returns \"0\"\n * ```\n */\nexport function nFormatter(\n num?: number,\n opts: { digits?: number; full?: boolean } = {\n digits: 1,\n },\n locale: string = \"en-US\",\n): string {\n if (!num) return \"0\";\n if (opts.full) {\n return Intl.NumberFormat(locale).format(num);\n }\n\n const rx = /\\.0+$|(\\.[0-9]*[1-9])0+$/;\n const digits = opts.digits ?? 1;\n\n // Handle negative magnitudes by formatting the absolute value and re-applying\n // the sign. Previously negatives with |num| >= 1000 collapsed to \"0\" because\n // the lookup never matched (every value in `lookup` is positive).\n const sign = num < 0 ? \"-\" : \"\";\n const abs = Math.abs(num);\n\n if (abs < 1) {\n return `${sign}${abs.toFixed(digits).replace(rx, \"$1\")}`;\n }\n\n const lookup = [\n { value: 1, symbol: \"\" },\n { value: 1e3, symbol: \"K\" },\n { value: 1e6, symbol: \"M\" },\n { value: 1e9, symbol: \"G\" },\n { value: 1e12, symbol: \"T\" },\n { value: 1e15, symbol: \"P\" },\n { value: 1e18, symbol: \"E\" },\n ];\n const item = lookup\n .slice()\n .reverse()\n .find((item) => abs >= item.value);\n return item\n ? `${sign}${(abs / item.value).toFixed(digits).replace(rx, \"$1\")}${item.symbol}`\n : \"0\";\n}\n","/**\n * Utility function for string normalization\n * Provides consistent string formatting by removing special characters and normalizing whitespace\n */\n\nimport { isDevelopment } from \"../../constants/development\";\nimport { logger } from \"../logging/logger\";\n\n/**\n * Normalizes a string by removing special characters and normalizing whitespace\n * Useful for cleaning user input, keys, and other string data\n *\n * @param key - The string to normalize\n * @returns A normalized string with special characters removed and whitespace normalized\n *\n * @example\n * ```ts\n * import { normalizeString } from '@/utils/functions';\n *\n * // Remove special characters\n * normalizeString('Hello\\u0000World')\n * // Returns \"Hello World\"\n *\n * // Normalize whitespace\n * normalizeString('Hello World')\n * // Returns \"hello world\"\n *\n * // Handle empty input\n * normalizeString('')\n * // Returns \"\"\n *\n * // Normalize case\n * normalizeString('HeLLo WoRLd')\n * // Returns \"hello world\"\n *\n * // Remove BOM and other special characters\n * normalizeString('\\uFEFFHello')\n * // Returns \"hello\"\n * ```\n */\nexport const normalizeString = (key: string): string => {\n if (!key) return \"\";\n\n const original = key;\n const normalized = key\n // Strip a leading UTF-8 BOM expressed either as the actual U+FEFF character\n // or as its raw byte sequence EF BB BF. (\\u escapes only take 4 hex digits,\n // so the previous \\uEFBBBF never matched the bytes.)\n .replace(/^\\uFEFF/, \"\")\n .replace(/^\\uFFFE/, \"\")\n .replace(/^[\\u00EF\\u00BB\\u00BF]+/, \"\")\n // biome-ignore lint/suspicious/noControlCharactersInRegex: handle null-byte + BOM prefixes\n .replace(/^[\\u0000\\uFEFF]{2}/, \"\")\n // biome-ignore lint/suspicious/noControlCharactersInRegex: handle null-byte + noncharacter BOM prefixes\n .replace(/^[\\uFFFE\\u0000]{2}/, \"\")\n .replace(/^\\u2028/, \"\")\n .replace(/^\\u2029/, \"\")\n // Remove any non-printable characters using a function instead of regex with control characters\n .replace(/./g, (char) => {\n const code = char.charCodeAt(0);\n return code <= 0x1f || (code >= 0x7f && code <= 0x9f) ? \"\" : char;\n })\n // Normalize whitespace\n .replace(/\\s+/g, \" \")\n .trim()\n // Optional: normalize case\n .toLowerCase();\n\n // Logging is gated behind an explicit env var (KUMIX_DEBUG_NORMALIZE) to avoid\n // accidentally dumping user input / secrets through the logger in dev.\n if (\n isDevelopment &&\n typeof process !== \"undefined\" &&\n process.env?.KUMIX_DEBUG_NORMALIZE &&\n original !== normalized\n ) {\n logger.log(\n `normalizeString: input changed (length ${original.length} -> ${normalized.length})`,\n );\n }\n\n return normalized;\n};\n","/**\n * Utility function for pluralizing words\n * Provides simple English pluralization based on count\n */\n\n/**\n * Pluralizes a word based on a count value\n * Returns singular form for count=1, plural form otherwise\n *\n * @param word - The word to pluralize\n * @param count - The count determining whether to use singular or plural form\n * @param options - Optional configuration\n * @param options.plural - Custom plural form (if not provided, 's' is appended)\n * @returns The appropriate singular or plural form based on count\n *\n * @example\n * ```ts\n * import { pluralize } from '@/utils/functions';\n *\n * // Basic usage\n * pluralize('item', 1)\n * // Returns \"item\"\n *\n * pluralize('item', 2)\n * // Returns \"items\"\n *\n * // With custom plural form\n * pluralize('category', 1)\n * // Returns \"category\"\n *\n * pluralize('category', 2, { plural: 'categories' })\n * // Returns \"categories\"\n *\n * // In a sentence\n * const count = 5;\n * `You have ${count} ${pluralize('message', count)}`\n * // Returns \"You have 5 messages\"\n * ```\n */\nexport const pluralize = (\n word: string,\n count: number,\n options: {\n plural?: string;\n } = {},\n) => {\n if (count === 1) {\n return word;\n }\n\n // Use custom plural form if provided, otherwise add 's'\n return options.plural || `${word}s`;\n};\n","/**\n * Utility function for regular expression handling\n * Provides safe string escaping for use in regular expressions\n */\n\n/**\n * Escapes special characters in a string for use in a regular expression\n * Ensures that special regex characters are treated as literals\n * Based on: https://stackoverflow.com/a/6969486\n *\n * @param str - The string to escape for regex use\n * @returns A string with all regex special characters escaped\n *\n * @example\n * ```ts\n * import { regexEscape } from '@/utils/functions';\n *\n * // Basic usage\n * regexEscape('hello.world')\n * // Returns \"hello\\.world\"\n *\n * // Escaping special characters\n * regexEscape('(test)[123]+?')\n * // Returns \"\\(test\\)\\[123\\]\\+\\?\"\n *\n * // Creating a safe regex from user input\n * const userInput = 'user.input+';\n * const safeRegex = new RegExp(regexEscape(userInput));\n * // Creates a regex that matches the literal string \"user.input+\"\n *\n * // Using in string replacement\n * const text = \"Hello (world)\";\n * const searchTerm = \"(world)\";\n * text.replace(new RegExp(regexEscape(searchTerm)), \"everyone\");\n * // Returns \"Hello everyone\"\n * ```\n */\nexport function regexEscape(str: string): string {\n return str.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n","/**\n * Utility function for string truncation\n * Provides a simple way to limit string length with ellipsis\n */\n\n/**\n * Truncates a string to a specified length and adds ellipsis\n * Handles null and undefined values gracefully\n *\n * @param str - The string to truncate\n * @param length - Maximum length of the truncated string (including ellipsis)\n * @returns Truncated string with ellipsis, or null if input is null/undefined\n *\n * @example\n * ```ts\n * import { truncate } from '@/utils/functions';\n *\n * // Basic usage\n * truncate('This is a long string that needs truncation', 20)\n * // Returns \"This is a long st...\"\n *\n * // String shorter than max length (no truncation)\n * truncate('Short string', 20)\n * // Returns \"Short string\"\n *\n * // With null input\n * truncate(null, 10)\n * // Returns null\n *\n * // With undefined input\n * truncate(undefined, 10)\n * // Returns null\n *\n * // Display truncated text in UI\n * const displayTitle = (title: string) => {\n * return truncate(title, 50) || 'Untitled';\n * };\n * ```\n */\nexport const truncate = (str: string | null | undefined, length: number): string | null => {\n if (!str) return null;\n if (str.length <= length) return str;\n // Ellipsis needs at least 4 chars to fit (\"x...\"); for smaller lengths, fall\n // back to a hard slice so the result never exceeds the requested length.\n const ELLIPSIS = \"...\";\n if (length <= ELLIPSIS.length) {\n return str.slice(0, length);\n }\n return `${str.slice(0, length - ELLIPSIS.length)}${ELLIPSIS}`;\n};\n","/**\n * Utility functions for smart URL truncation\n * Provides intelligent truncation that preserves important parts of URLs\n */\n\nimport { truncate } from \"./truncate\";\n\n/**\n * Truncates a domain name while preserving the TLD\n * Ensures the domain remains recognizable even when shortened\n *\n * @param domain - The domain name to truncate\n * @param maxLength - Maximum length for the truncated domain\n * @returns A truncated domain with preserved TLD\n *\n * @example\n * truncateDomain('verylongdomain.com', 10)\n * // Returns \"verylong...com\"\n */\nconst truncateDomain = (domain: string, maxLength: number): string => {\n const parts = domain.split(\".\");\n const tld = parts.pop() || \"\";\n const rest = parts.join(\".\");\n\n return `${rest.slice(0, maxLength)}...${tld}`;\n};\n\n/**\n * Intelligently truncates a URL while preserving important parts\n * Dynamically adjusts based on the length of the domain and path,\n * giving priority to the path and truncating the domain if necessary,\n * while ensuring the domain still shows at least 8 characters\n *\n * @param link - The URL or path to truncate\n * @param maxLength - Maximum length for the truncated result\n * @returns A smartly truncated URL that preserves important parts\n *\n * @example\n * ```ts\n * import { smartTruncate } from '@/utils/functions';\n *\n * // Basic usage\n * smartTruncate('example.com/very/long/path/to/resource', 25)\n * // Returns \"exam...com/very/long/path/to\"\n *\n * // Short URL (no truncation needed)\n * smartTruncate('example.com/path', 25)\n * // Returns \"example.com/path\"\n *\n * // Very long domain with short path\n * smartTruncate('verylongdomainname.com/path', 25)\n * // Returns \"verylong...com/path\"\n *\n * // Very long path with short domain\n * smartTruncate('short.com/very/long/path/to/resource', 25)\n * // Returns \"short.com/very/long/path/to\"\n * ```\n */\nexport const smartTruncate = (link: string, maxLength: number): string => {\n if (!link) return \"\";\n if (maxLength <= 0) return \"\";\n if (link.length <= maxLength) return link;\n\n const [domain, ...pathParts] = link.split(\"/\");\n const path = pathParts.join(\"/\");\n const minDomainLength = 8;\n\n // If the requested length can't even fit the minimum domain reservation,\n // bail out with a hard slice of the whole string. Going below zero would\n // otherwise feed `truncate` a negative length and slice from the end.\n if (maxLength < minDomainLength) {\n return link.slice(0, maxLength);\n }\n\n // calculate max path length\n const maxPathLength = maxLength - minDomainLength;\n\n // Truncate path. `truncate` returns null for falsy input, so handle the\n // \"no path\" case explicitly to avoid emitting `${domain}/null`.\n const truncatedPath = path ? truncate(path, maxPathLength) : null;\n if (!truncatedPath) {\n return truncateDomain(domain, maxLength);\n }\n\n // Truncate domain if necessary, preserving TLD\n const truncatedDomain = truncateDomain(domain, maxLength - truncatedPath.length);\n\n return `${truncatedDomain}/${truncatedPath}`;\n};\n","/**\n * Utility function for safe string trimming\n * Provides type-safe trimming that handles non-string inputs gracefully\n */\n\n/**\n * Safely trims a string value, returning non-string values unchanged\n * Useful for processing user input or data from external sources\n *\n * @param u - The value to trim, can be any type\n * @returns The trimmed string if input is a string, otherwise the original value\n *\n * @example\n * ```ts\n * import { trim } from '@/utils/functions';\n *\n * // With string input\n * trim(' hello world ')\n * // Returns \"hello world\"\n *\n * // With non-string input\n * trim(123)\n * // Returns 123 (unchanged)\n *\n * trim(null)\n * // Returns null (unchanged)\n *\n * // Useful for processing form data\n * const processFormData = (data: Record<string, unknown>) => {\n * return Object.fromEntries(\n * Object.entries(data).map(([key, value]) => [key, trim(value)])\n * );\n * };\n * ```\n */\nexport const trim = (u: unknown): unknown => (typeof u === \"string\" ? u.trim() : u);\n","/**\n * URL validation utilities\n * Provides functions for validating URL strings and checking URL validity\n */\n\n/**\n * Checks if a string is a valid URL.\n *\n * By default rejects non-fetchable schemes (`javascript:`, `data:`, `file:`,\n * `vbscript:`) to avoid XSS via redirect/href validation. Set `allowAnyScheme`\n * to accept any scheme the URL parser accepts.\n *\n * Uses the URL constructor for validation.\n *\n * @param url - The string to check\n * @param options - Validation options\n * @param options.allowAnyScheme - When true, accept any scheme (defaults to false)\n * @returns True if the string is a valid URL, false otherwise\n *\n * @example\n * ```typescript\n * import { isValidUrl } from '@kumix/utils';\n *\n * // Valid URLs\n * isValidUrl('https://example.com'); // true\n * isValidUrl('http://localhost:3000'); // true\n * isValidUrl('ftp://files.example.com'); // true\n *\n * // Invalid / unsafe URLs (rejected by default)\n * isValidUrl('javascript:alert(1)'); // false\n * isValidUrl('example.com'); // false (missing protocol)\n *\n * // Use in form validation\n * function validateUrlInput(input: string) {\n * if (!isValidUrl(input)) {\n * return 'Please enter a valid URL';\n * }\n * return null;\n * }\n * ```\n */\nexport const isValidUrl = (url: string, options: { allowAnyScheme?: boolean } = {}): boolean => {\n if (!url || typeof url !== \"string\") return false;\n try {\n const parsed = new URL(url);\n if (options.allowAnyScheme) return true;\n // Block schemes that are unsafe when fed back into href/redirect targets.\n const blocked = [\"javascript:\", \"data:\", \"vbscript:\", \"file:\"];\n const scheme = parsed.protocol.toLowerCase();\n if (blocked.some((b) => scheme === b)) {\n return false;\n }\n return true;\n } catch (_) {\n return false;\n }\n};\n","/**\n * Utility functions for domain name operations\n * Provides tools for domain validation, parsing, and generation\n */\n\nimport slugify from \"@sindresorhus/slugify\";\n\nimport { ccTLDs } from \"../../constants/domain/cctlds\";\nimport { SECOND_LEVEL_DOMAINS } from \"../../constants/domain/second\";\nimport { SPECIAL_APEX_DOMAINS } from \"../../constants/domain/special\";\nimport { isValidUrl } from \"./url-validation\";\n\n/**\n * Generates a domain name from a given string\n * Attempts to create a short, memorable domain using various strategies\n *\n * @param name - The name to generate a domain from\n * @param extension - The domain extension to use (default: \"link\")\n * @returns A generated domain name, or empty string if generation fails\n *\n * @example\n * ```ts\n * import { generateDomainFromName } from '@/utils/functions';\n *\n * // Basic usage with default extension (.link)\n * generateDomainFromName('My Cool Project')\n * // Returns \"mycoolproject.link\"\n *\n * // With custom extension\n * generateDomainFromName('My Cool Project', 'com')\n * // Returns \"mycoolproject.com\"\n *\n * // ccTLD fallback only applies when the trailing 2 chars form a known ccTLD;\n * // for \"Canada\" the trailing 2 chars are \"da\" (not a ccTLD), so the default\n * // extension is used.\n * generateDomainFromName('Canada')\n * // Returns \"canada.link\"\n *\n * // With vowels removed if needed\n * generateDomainFromName('Digital', 'io')\n * // Returns \"dgtl.io\"\n * ```\n */\nexport const generateDomainFromName = (name: string, extension: string = \"link\"): string => {\n const normalizedName = slugify(name, { separator: \"\" });\n if (normalizedName.length < 3) {\n return \"\";\n }\n if (ccTLDs.has(normalizedName.slice(-2))) {\n return `${normalizedName.slice(0, -2)}.${normalizedName.slice(-2)}`;\n }\n // remove vowels\n const devowel = normalizedName.replace(/[aeiou]/g, \"\");\n if (devowel.length >= 3 && ccTLDs.has(devowel.slice(-2))) {\n return `${devowel.slice(0, -2)}.${devowel.slice(-2)}`;\n }\n\n const shortestString = [normalizedName, devowel].reduce((a, b) => (a.length < b.length ? a : b));\n\n return `${shortestString}.${extension}`;\n};\n\n/**\n * Regular expression for validating domain names\n * Ensures domains follow standard naming conventions\n *\n * @example\n * ```ts\n * import { validDomainRegex } from '@/utils/functions';\n *\n * // Check if a domain is valid\n * const isValidDomain = (domain: string) => validDomainRegex.test(domain);\n *\n * isValidDomain('example.com') // true\n * isValidDomain('sub.example.co.uk') // true\n * isValidDomain('invalid domain') // false\n * ```\n */\nexport const validDomainRegex = new RegExp(\n /^([a-zA-Z0-9]([a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\\.)+[a-zA-Z]{2,}$/,\n);\n\n/**\n * Regular expression for validating URL slugs\n * Ensures slugs only contain alphanumeric characters and hyphens\n *\n * @example\n * ```ts\n * import { validSlugRegex } from '@/utils/functions';\n *\n * // Check if a slug is valid\n * const isValidSlug = (slug: string) => validSlugRegex.test(slug);\n *\n * isValidSlug('my-page') // true\n * isValidSlug('about123') // true\n * isValidSlug('invalid_slug') // false (contains underscore)\n * ```\n */\nexport const validSlugRegex = new RegExp(/^[a-zA-Z0-9-]+$/);\n\n/**\n * Extracts the subdomain from a full domain name\n *\n * @param name - The full domain name (e.g., \"sub.example.com\")\n * @param apexName - The apex domain (e.g., \"example.com\")\n * @returns The subdomain or null if there is no subdomain\n *\n * @example\n * ```ts\n * import { getSubdomain } from '@/utils/functions';\n *\n * // Get subdomain\n * getSubdomain('app.example.com', 'example.com')\n * // Returns \"app\"\n *\n * // Multiple levels of subdomains\n * getSubdomain('dev.app.example.com', 'example.com')\n * // Returns \"dev.app\"\n *\n * // No subdomain\n * getSubdomain('example.com', 'example.com')\n * // Returns null\n * ```\n */\nexport const getSubdomain = (name: string, apexName: string): string | null => {\n if (name === apexName) return null;\n return name.slice(0, name.length - apexName.length - 1);\n};\n\n/**\n * Extracts the apex (root) domain from a URL\n * Handles special cases like second-level TLDs and website builder domains\n *\n * @param url - The URL to extract the apex domain from\n * @returns The apex domain, or empty string if extraction fails\n *\n * @example\n * ```ts\n * import { getApexDomain } from '@/utils/functions';\n *\n * // Basic usage\n * getApexDomain('https://example.com/page')\n * // Returns \"example.com\"\n *\n * // With subdomain\n * getApexDomain('https://app.example.com')\n * // Returns \"example.com\"\n *\n * // With second-level TLD\n * getApexDomain('https://example.co.uk')\n * // Returns \"example.co.uk\"\n *\n * // With special apex domain\n * getApexDomain('https://myproject.vercel.app')\n * // Returns \"myproject.vercel.app\"\n *\n * // Special case for YouTube\n * getApexDomain('https://youtu.be/12345')\n * // Returns \"youtube.com\"\n * ```\n */\nexport const getApexDomain = (url: string): string => {\n let domain = \"\";\n try {\n // replace any custom scheme (e.g. notion://) with https://\n // use the URL constructor to get the hostname\n domain = new URL(url.replace(/^[a-zA-Z]+:\\/\\//, \"https://\")).hostname;\n } catch (_) {\n return \"\";\n }\n if (domain === \"youtu.be\") return \"youtube.com\";\n\n const parts = domain.split(\".\");\n if (parts.length > 2) {\n if (\n // if this is a second-level TLD (e.g. co.uk, .com.ua, .org.tt), we need to return the last 3 parts\n (SECOND_LEVEL_DOMAINS.has(parts[parts.length - 2]) && ccTLDs.has(parts[parts.length - 1])) ||\n // if it's a special subdomain for website builders (e.g. weathergpt.vercel.app/)\n SPECIAL_APEX_DOMAINS.has(parts.slice(-2).join(\".\"))\n ) {\n return parts.slice(-3).join(\".\");\n }\n // otherwise, it's a subdomain (e.g. kumix.vercel.app), so we return the last 2 parts\n return parts.slice(-2).join(\".\");\n }\n // if it's a normal domain (e.g. kumix.io), we return the domain\n return domain;\n};\n\n/**\n * Removes the \"www.\" prefix from a domain if present\n * Attempts to parse the input as a URL if it's not already a valid URL\n *\n * @param url - The URL or domain to process\n * @returns The domain without \"www.\" prefix, or null if parsing fails\n *\n * @example\n * ```ts\n * import { getDomainWithoutWWW } from '@/utils/functions';\n *\n * // With www prefix\n * getDomainWithoutWWW('https://www.example.com')\n * // Returns \"example.com\"\n *\n * // Without www prefix\n * getDomainWithoutWWW('https://example.com')\n * // Returns \"example.com\"\n *\n * // With just domain (no protocol)\n * getDomainWithoutWWW('www.example.com')\n * // Returns \"example.com\"\n *\n * // Invalid input\n * getDomainWithoutWWW('not a domain')\n * // Returns null\n * ```\n */\nexport const getDomainWithoutWWW = (url: string): string | null | undefined => {\n if (isValidUrl(url)) {\n return new URL(url).hostname.replace(/^www\\./, \"\");\n }\n try {\n if (url.includes(\".\") && !url.includes(\" \")) {\n return new URL(`https://${url}`).hostname.replace(/^www\\./, \"\");\n }\n } catch (_) {\n return null;\n }\n};\n","/**\n * Utility functions for constructing URLs and links\n * Provides tools for building URLs with various options and formats\n */\n\n/**\n * Constructs a URL with various options\n * Handles special cases like root paths and optional search parameters\n *\n * @param options - Configuration options for the URL\n * @param options.domain - The domain name (optional)\n * @param options.key - The path key or slug (optional)\n * @param options.pretty - Whether to remove protocol for display purposes (optional)\n * @param options.searchParams - URL search parameters to include (optional)\n * @returns A formatted URL string, or empty string if no domain is provided\n *\n * @example\n * ```ts\n * import { linkConstructor } from '@/utils/functions';\n *\n * // Basic usage\n * linkConstructor({ domain: 'example.com', key: 'page' })\n * // Returns \"https://example.com/page\"\n *\n * // Root path (no key)\n * linkConstructor({ domain: 'example.com' })\n * // Returns \"https://example.com\"\n *\n * // With special _root key\n * linkConstructor({ domain: 'example.com', key: '_root' })\n * // Returns \"https://example.com\"\n *\n * // With search parameters\n * linkConstructor({\n * domain: 'example.com',\n * key: 'search',\n * searchParams: { q: 'query', page: '1' }\n * })\n * // Returns \"https://example.com/search?q=query&page=1\"\n *\n * // Pretty format (without protocol)\n * linkConstructor({ domain: 'example.com', key: 'about', pretty: true })\n * // Returns \"example.com/about\"\n *\n * // With internationalized domain name\n * linkConstructor({ domain: 'mañana.com', key: 'café' })\n * // Returns \"https://xn--maana-pta.com/xn--caf-dma\" (punycode encoded)\n * ```\n */\nexport function linkConstructor({\n domain,\n key,\n pretty,\n searchParams,\n}: {\n domain?: string;\n key?: string;\n pretty?: boolean;\n searchParams?: Record<string, string>;\n}) {\n if (!domain) {\n return \"\";\n }\n\n let url = `https://${domain}${key && key !== \"_root\" ? `/${key}` : \"\"}`;\n\n if (searchParams) {\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(searchParams)) {\n search.set(key, value);\n }\n url += `?${search.toString()}`;\n }\n\n return pretty ? url.replace(/^https?:\\/\\//, \"\") : url;\n}\n\n/**\n * Simplified version of linkConstructor with fewer options\n * Creates a basic URL without extra encoding or search parameters\n *\n * @param options - Configuration options for the URL\n * @param options.domain - The domain name\n * @param options.key - The path key or slug\n * @returns A formatted URL string\n *\n * @example\n * ```ts\n * import { linkConstructorSimple } from '@/utils/functions';\n *\n * // Basic usage\n * linkConstructorSimple({ domain: 'example.com', key: 'page' })\n * // Returns \"https://example.com/page\"\n *\n * // With special _root key\n * linkConstructorSimple({ domain: 'example.com', key: '_root' })\n * // Returns \"https://example.com\"\n * ```\n */\nexport function linkConstructorSimple({ domain, key }: { domain: string; key: string }) {\n return `https://${domain}${key === \"_root\" ? \"\" : `/${key}`}`;\n}\n\n// /**\n// * Returns the base URL of the site based on environment variables.\n// *\n// * @param context - The context of the base URL (main, app, portal, admin)\n// * @returns A string representing the base URL of the site.\n// *\n// * @example\n// * ```ts\n// * const url = baseUrl();\n// * // \"https://example.com\" (from env)\n// * // or \"https://your-vercel-project.vercel.app\"\n// * // or \"http://localhost:3000\"\n// * ```\n// */\n// export function baseUrl(context: 'main' | 'app' | 'portal' | 'admin' = 'main') {\n// const url =\n// context === 'app'\n// ? APP_DOMAIN\n// : context === 'portal'\n// ? PORTAL_DOMAIN\n// : context === 'admin'\n// ? ADMIN_DOMAIN\n// : MAIN_DOMAIN;\n// return url;\n// }\n","/**\n * URL search parameters utilities\n * Provides functions for extracting and manipulating URL search parameters\n */\n\n/**\n * Extracts search parameters from a URL as a simple object\n * Converts URLSearchParams to a plain JavaScript object\n *\n * @param url - The URL to extract search parameters from\n * @returns An object with search parameters as key-value pairs\n *\n * @example\n * ```typescript\n * import { getSearchParams } from '@kumix/utils';\n *\n * // Basic usage\n * getSearchParams('https://example.com?name=John&age=30');\n * // Returns { name: 'John', age: '30' }\n *\n * // With multiple parameters\n * getSearchParams('https://example.com/search?q=test&page=2&limit=10');\n * // Returns { q: 'test', page: '2', limit: '10' }\n *\n * // Note: If the same parameter appears multiple times, only the last value is kept\n * getSearchParams('https://example.com?tag=js&tag=react');\n * // Returns { tag: 'react' }\n *\n * // Use in form initialization\n * const urlParams = getSearchParams(window.location.href);\n * const initialFormData = {\n * search: urlParams.q || '',\n * category: urlParams.category || 'all'\n * };\n *\n * // Use in API calls\n * const params = getSearchParams(requestUrl);\n * const response = await api.search(params);\n * ```\n */\nexport const getSearchParams = (url: string): Record<string, string> => {\n // Create a params object\n const params = {} as Record<string, string>;\n\n // Wrap in try/catch for consistency with getParamsFromURL — a malformed\n // (relative, empty) URL used to throw TypeError and crash the caller.\n try {\n new URL(url).searchParams.forEach((val, key) => {\n params[key] = val;\n });\n } catch {\n // return whatever was collected (empty object on parse failure)\n }\n\n return params;\n};\n\n/**\n * Extracts search parameters from a URL, handling multiple values as arrays\n * Similar to getSearchParams but preserves multiple occurrences of the same parameter\n *\n * @param url - The URL to extract search parameters from\n * @returns An object with search parameters as key-value pairs, with arrays for repeated parameters\n *\n * @example\n * ```typescript\n * import { getSearchParamsWithArray } from '@kumix/utils';\n *\n * // With single parameters\n * getSearchParamsWithArray('https://example.com?name=John&age=30');\n * // Returns { name: 'John', age: '30' }\n *\n * // With repeated parameters\n * getSearchParamsWithArray('https://example.com?tag=js&tag=react&tag=typescript');\n * // Returns { tag: ['js', 'react', 'typescript'] }\n *\n * // Mixed single and repeated parameters\n * getSearchParamsWithArray('https://example.com/search?q=test&filter=name&filter=date');\n * // Returns { q: 'test', filter: ['name', 'date'] }\n *\n * // Use in filtering systems\n * const params = getSearchParamsWithArray(window.location.href);\n * const filters = Array.isArray(params.filter) ? params.filter : [params.filter].filter(Boolean);\n * const results = data.filter(item =>\n * filters.every(filter => item.tags.includes(filter))\n * );\n *\n * // Use in multi-select forms\n * const urlParams = getSearchParamsWithArray(url);\n * const selectedCategories = Array.isArray(urlParams.category)\n * ? urlParams.category\n * : urlParams.category ? [urlParams.category] : [];\n * ```\n */\nexport const getSearchParamsWithArray = (url: string): Record<string, string | string[]> => {\n const params = {} as Record<string, string | string[]>;\n\n try {\n new URL(url).searchParams.forEach((val, key) => {\n if (key in params) {\n const param = params[key];\n if (Array.isArray(param)) {\n param.push(val);\n } else {\n params[key] = [param as string, val];\n }\n } else {\n params[key] = val;\n }\n });\n } catch {\n // return whatever was collected (empty object on parse failure)\n }\n\n return params;\n};\n\n/**\n * Extracts non-empty search parameters from a URL\n * Similar to getSearchParams but filters out empty values\n *\n * @param url - The URL to extract search parameters from\n * @returns An object with non-empty search parameters as key-value pairs\n *\n * @example\n * ```typescript\n * import { getParamsFromURL } from '@kumix/utils';\n *\n * // Basic usage\n * getParamsFromURL('https://example.com?name=John&age=30');\n * // Returns { name: 'John', age: '30' }\n *\n * // With empty parameters (these are filtered out)\n * getParamsFromURL('https://example.com?name=John&empty=&blank=');\n * // Returns { name: 'John' }\n *\n * // With invalid URL\n * getParamsFromURL('not-a-url');\n * // Returns {}\n *\n * // With empty URL\n * getParamsFromURL('');\n * // Returns {}\n *\n * // Use in form validation\n * const params = getParamsFromURL(window.location.href);\n * const hasRequiredParams = 'id' in params && 'token' in params;\n * if (!hasRequiredParams) {\n * throw new Error('Missing required parameters');\n * }\n *\n * // Use in analytics\n * const trackingParams = getParamsFromURL(referrerUrl);\n * if (Object.keys(trackingParams).length > 0) {\n * analytics.track('page_view_with_params', trackingParams);\n * }\n * ```\n */\nexport const getParamsFromURL = (url: string): Record<string, string> => {\n if (!url) return {};\n try {\n const params = new URL(url).searchParams;\n const paramsObj: Record<string, string> = {};\n for (const [key, value] of params.entries()) {\n if (value && value !== \"\") {\n paramsObj[key] = value;\n }\n }\n return paramsObj;\n } catch (_) {\n return {};\n }\n};\n","/**\n * URL conversion utilities\n * Provides functions for converting strings to URLs and creating absolute URLs\n */\n\n// import {\n// ADMIN_DOMAIN,\n// APP_DOMAIN,\n// MAIN_DOMAIN,\n// PORTAL_DOMAIN,\n// } from '../../constants';\nimport { isValidUrl } from \"./url-validation\";\n\n// /**\n// * Constructs an absolute URL based on the base application URL\n// *\n// * Safely combines a base URL with a relative path, handling edge cases\n// * like missing slashes and ensuring proper URL formation.\n// *\n// * @param path - The relative path to append to the base URL\n// * @param context - The context of the base URL (main, app, portal, admin)\n// * @returns A string representing the absolute URL\n// *\n// * @example\n// * ```typescript\n// * import { absoluteUrl } from '@kumix/utils';\n// *\n// * // With environment variable\n// * const profileUrl = absoluteUrl('/profile/123');\n// * // Result: 'https://example.com/profile/123'\n// *\n// * // With explicit base URL\n// * const apiUrl = absoluteUrl('/v1/users');\n// * // Result: 'https://api.example.com/v1/users'\n// *\n// * // Handles missing slashes\n// * const url1 = absoluteUrl('/path'); // 'https://example.com/path'\n// * const url2 = absoluteUrl('path'); // 'https://example.com/path'\n// *\n// * // Use in API calls\n// * const response = await fetch(absoluteUrl('/api/users'));\n// *\n// * // Use in redirects\n// * router.push(absoluteUrl('/dashboard'));\n// * ```\n// */\n// export function absoluteUrl(\n// path: string,\n// context: 'main' | 'app' | 'portal' | 'admin' = 'main',\n// ): string {\n// const url =\n// context === 'app'\n// ? APP_DOMAIN\n// : context === 'portal'\n// ? PORTAL_DOMAIN\n// : context === 'admin'\n// ? ADMIN_DOMAIN\n// : MAIN_DOMAIN;\n// const baseUrl = url + '/';\n\n// if (baseUrl && baseUrl !== '/') {\n// return baseUrl + path;\n// } else {\n// return path;\n// }\n// }\n\n/**\n * Attempts to convert a string to a valid URL\n * If the string is not a valid URL but looks like a domain, prepends https://\n *\n * @param str - The string to convert\n * @returns A valid URL string or the original string if conversion fails\n *\n * @example\n * ```typescript\n * import { getUrlFromString } from '@kumix/utils';\n *\n * // Already valid URL\n * getUrlFromString('https://example.com'); // \"https://example.com\"\n *\n * // Domain without protocol\n * getUrlFromString('example.com'); // \"https://example.com\"\n * getUrlFromString('subdomain.example.com'); // \"https://subdomain.example.com\"\n *\n * // Not a URL\n * getUrlFromString('not a url'); // \"not a url\" (unchanged)\n * getUrlFromString('just text'); // \"just text\" (unchanged)\n *\n * // Use in link processing\n * function processUserInput(input: string) {\n * const url = getUrlFromString(input);\n * if (isValidUrl(url)) {\n * return `<a href=\"${url}\">${input}</a>`;\n * }\n * return input;\n * }\n * ```\n */\nexport const getUrlFromString = (str: string): string => {\n if (isValidUrl(str)) return str;\n try {\n if (str.includes(\".\") && !str.includes(\" \")) {\n return new URL(`https://${str}`).toString();\n }\n } catch (_) {\n // Ignore invalid URLs\n }\n return str;\n};\n\n/**\n * Attempts to convert a string to a URL object\n * If the string is not a valid URL but looks like a domain, prepends https://\n *\n * @param str - The string to convert\n * @returns A URL object or null if conversion fails\n *\n * @example\n * ```typescript\n * import { getUrlObjFromString } from '@kumix/utils';\n *\n * // Already valid URL\n * const url1 = getUrlObjFromString('https://example.com');\n * // Returns URL object for \"https://example.com\"\n *\n * // Domain without protocol\n * const url2 = getUrlObjFromString('example.com');\n * // Returns URL object for \"https://example.com\"\n *\n * // Not a URL\n * const url3 = getUrlObjFromString('not a url');\n * // Returns null\n *\n * // Use for URL manipulation\n * const urlObj = getUrlObjFromString('example.com');\n * if (urlObj) {\n * urlObj.searchParams.set('utm_source', 'newsletter');\n * console.log(urlObj.toString()); // \"https://example.com?utm_source=newsletter\"\n * }\n *\n * // Extract URL components\n * const urlObj = getUrlObjFromString('https://api.example.com/v1/users');\n * if (urlObj) {\n * console.log(urlObj.hostname); // \"api.example.com\"\n * console.log(urlObj.pathname); // \"/v1/users\"\n * }\n * ```\n */\nexport const getUrlObjFromString = (str: string): URL | null => {\n if (isValidUrl(str)) return new URL(str);\n try {\n if (str.includes(\".\") && !str.includes(\" \")) {\n return new URL(`https://${str}`);\n }\n } catch (_) {\n // Ignore invalid URLs\n }\n return null;\n};\n\n/**\n * Attempts to convert a string to a valid URL, returning null if invalid\n * Similar to getUrlFromString but returns null instead of the original string on failure\n *\n * @param str - The string to convert\n * @returns A valid URL string or null if conversion fails\n *\n * @example\n * ```typescript\n * import { getUrlFromStringIfValid } from '@kumix/utils';\n *\n * // Already valid URL\n * getUrlFromStringIfValid('https://example.com'); // \"https://example.com\"\n *\n * // Domain without protocol\n * getUrlFromStringIfValid('example.com'); // \"https://example.com\"\n *\n * // Not a URL\n * getUrlFromStringIfValid('not a url'); // null\n *\n * // Use in conditional logic\n * const userInput = 'example.com';\n * const validUrl = getUrlFromStringIfValid(userInput);\n * if (validUrl) {\n * // Process as valid URL\n * window.open(validUrl, '_blank');\n * } else {\n * // Handle invalid input\n * alert('Please enter a valid URL');\n * }\n *\n * // Filter valid URLs from array\n * const inputs = ['example.com', 'not a url', 'https://test.com'];\n * const validUrls = inputs\n * .map(getUrlFromStringIfValid)\n * .filter(Boolean); // ['https://example.com', 'https://test.com']\n * ```\n */\nexport const getUrlFromStringIfValid = (str: string): string | null => {\n if (isValidUrl(str)) return str;\n try {\n if (str.includes(\".\") && !str.includes(\" \")) {\n return new URL(`https://${str}`).toString();\n }\n } catch (_) {\n // Ignore invalid URLs\n }\n return null;\n};\n","/**\n * URL formatting utilities\n * Provides functions for formatting URLs and generating URL-friendly slugs\n */\n\n/**\n * Formats a URL for display by removing protocol, www prefix, and trailing slash\n * Creates a cleaner, more user-friendly URL representation\n *\n * @param url - The URL to format\n * @returns A formatted URL string without protocol, www prefix, and trailing slash\n *\n * @example\n * ```typescript\n * import { getPrettyUrl } from '@kumix/utils';\n *\n * // Remove protocol and www\n * getPrettyUrl('https://www.example.com');\n * // Returns \"example.com\"\n *\n * // Remove trailing slash\n * getPrettyUrl('https://example.com/');\n * // Returns \"example.com\"\n *\n * // With path\n * getPrettyUrl('https://www.example.com/path/to/page/');\n * // Returns \"example.com/path/to/page\"\n *\n * // With subdomain\n * getPrettyUrl('https://api.example.com/v1');\n * // Returns \"api.example.com/v1\"\n *\n * // With null or undefined\n * getPrettyUrl(null);\n * // Returns \"\"\n *\n * // Use in UI components\n * function LinkDisplay({ url }: { url: string }) {\n * return <span className=\"text-gray-500\">{getPrettyUrl(url)}</span>;\n * }\n *\n * // Use in breadcrumbs\n * const breadcrumb = getPrettyUrl(currentUrl).split('/');\n * ```\n */\nexport const getPrettyUrl = (url?: string | null): string => {\n if (!url) return \"\";\n // remove protocol (http/https) and the leading www. host label only.\n // also remove trailing slash\n return url\n .replace(/(^\\w+:|^)\\/\\//, \"\")\n .replace(/^www\\./, \"\")\n .replace(/\\/$/, \"\");\n};\n\n/**\n * Generates a URL-friendly slug from a given title\n *\n * Converts any string into a clean, URL-safe slug by removing special characters,\n * normalizing unicode, and replacing spaces with hyphens. Perfect for creating\n * SEO-friendly URLs from titles, names, or other text content.\n *\n * @param title - The title to convert into a slug (e.g., \"Write a Proposal\")\n * @returns A slug string (e.g., \"write-a-proposal\")\n *\n * @example\n * ```typescript\n * import { getSlug } from '@kumix/utils';\n *\n * // Basic usage\n * getSlug('Hello World'); // 'hello-world'\n * getSlug('Write a Proposal'); // 'write-a-proposal'\n *\n * // Handles special characters\n * getSlug('Café & Restaurant!'); // 'cafe-restaurant'\n * getSlug('100% Success Rate'); // '100-success-rate'\n *\n * // Handles unicode and diacritics\n * getSlug('Résumé'); // 'resume'\n * getSlug('Naïve Approach'); // 'naive-approach'\n *\n * // Edge cases\n * getSlug(''); // ''\n * getSlug(' '); // ''\n * getSlug('---'); // ''\n * getSlug('Multiple Spaces'); // 'multiple-spaces'\n *\n * // Use in blog post URLs\n * const blogPost = {\n * title: 'How to Build a SaaS Application',\n * slug: getSlug('How to Build a SaaS Application') // 'how-to-build-a-saas-application'\n * };\n *\n * // Use in file naming\n * const fileName = `${getSlug(documentTitle)}.pdf`;\n *\n * // Use in route generation\n * const route = `/blog/${getSlug(post.title)}`;\n * ```\n */\nexport function getSlug(title: string): string {\n // Return empty string for invalid input\n if (!title || typeof title !== \"string\") {\n return \"\";\n }\n\n return title\n .toLowerCase() // Convert to lowercase for consistency\n .trim() // Remove leading/trailing whitespace\n .normalize(\"NFD\") // Normalize unicode (e.g., \"é\" -> \"e\")\n .replace(/[\\u0300-\\u036f]/g, \"\") // Remove diacritics\n .replace(/[^a-z0-9\\s-]/g, \"\") // Remove special characters except spaces/hyphens\n .replaceAll(/\\s+/g, \"-\") // Replace spaces with single hyphen\n .replace(/-+/g, \"-\") // Collapse multiple hyphens\n .replace(/^-|-$/g, \"\"); // Remove leading/trailing hyphens\n}\n","/**\n * UTM parameters utilities\n * Provides functions for handling UTM tracking parameters in URLs\n */\n\n/**\n * Standard UTM parameters and referral tags used in marketing campaigns\n * Provides a type-safe list of recognized UTM parameters\n *\n * @example\n * ```typescript\n * import { UTMTags } from '@kumix/utils';\n *\n * // Use in type definitions\n * type UTMParams = Partial<Record<typeof UTMTags[number], string>>;\n *\n * // Check if a parameter is a valid UTM tag\n * const isValidUTMTag = (tag: string): boolean =>\n * UTMTags.includes(tag as any);\n *\n * // Access specific tags\n * console.log(UTMTags[0]); // 'utm_source'\n *\n * // Generate form fields for UTM parameters\n * const utmFields = UTMTags.map(tag => ({\n * name: tag,\n * label: tag.replace('utm_', 'UTM ').replace(/\\b\\w/g, l => l.toUpperCase())\n * }));\n * ```\n */\nexport const UTMTags = [\n \"utm_source\",\n \"utm_medium\",\n \"utm_campaign\",\n \"utm_term\",\n \"utm_content\",\n \"ref\",\n] as const;\n\n/**\n * Metadata for UTM parameters with display names and examples\n * Provides human-readable information about each UTM parameter\n *\n * @example\n * ```typescript\n * import { paramsMetadata } from '@kumix/utils';\n *\n * // Access parameter metadata\n * const sourceParam = paramsMetadata.find(param => param.key === 'utm_source');\n * console.log(sourceParam);\n * // Returns { display: 'UTM Source', key: 'utm_source', examples: 'google, twitter' }\n *\n * // Generate form fields for UTM parameters\n * const formFields = paramsMetadata.map(param => ({\n * id: param.key,\n * label: param.display,\n * placeholder: `e.g., ${param.examples}`\n * }));\n *\n * // Find a parameter by display name\n * const findParamByDisplay = (display: string) =>\n * paramsMetadata.find(param => param.display === display);\n *\n * // Create help text for users\n * const helpText = paramsMetadata.map(param =>\n * `${param.display}: ${param.examples}`\n * ).join('\\n');\n * ```\n */\nexport const paramsMetadata = [\n { display: \"UTM Source\", key: \"utm_source\", examples: \"google, twitter\" },\n { display: \"UTM Medium\", key: \"utm_medium\", examples: \"social, email\" },\n { display: \"UTM Campaign\", key: \"utm_campaign\", examples: \"summer sale\" },\n { display: \"UTM Term\", key: \"utm_term\", examples: \"blue shoes\" },\n { display: \"UTM Content\", key: \"utm_content\", examples: \"logo link\" },\n { display: \"Referral (ref)\", key: \"ref\", examples: \"google, twitter\" },\n];\n\n/**\n * Constructs a URL with UTM parameters\n * Adds or updates UTM parameters in a URL, handling empty values\n *\n * @param url - The base URL to add UTM parameters to\n * @param utmParams - Object containing UTM parameters as key-value pairs\n * @returns The URL with UTM parameters added, or empty string if URL is invalid\n *\n * @example\n * ```typescript\n * import { constructURLFromUTMParams } from '@kumix/utils';\n *\n * // Add UTM parameters to a URL\n * constructURLFromUTMParams('https://example.com', {\n * utm_source: 'twitter',\n * utm_medium: 'social',\n * utm_campaign: 'summer_sale'\n * });\n * // Returns \"https://example.com?utm_source=twitter&utm_medium=social&utm_campaign=summer_sale\"\n *\n * // Update existing UTM parameters\n * constructURLFromUTMParams('https://example.com?utm_source=google', {\n * utm_source: 'twitter',\n * utm_medium: 'social'\n * });\n * // Returns \"https://example.com?utm_source=twitter&utm_medium=social\"\n *\n * // Remove a UTM parameter by setting it to empty string\n * constructURLFromUTMParams('https://example.com?utm_source=google&utm_medium=cpc', {\n * utm_medium: ''\n * });\n * // Returns \"https://example.com?utm_source=google\"\n *\n * // With invalid URL\n * constructURLFromUTMParams('', { utm_source: 'twitter' });\n * // Returns \"\"\n *\n * // Use in link generation\n * const campaignUrl = constructURLFromUTMParams(baseUrl, {\n * utm_source: 'newsletter',\n * utm_medium: 'email',\n * utm_campaign: 'product_launch'\n * });\n * ```\n */\nexport const constructURLFromUTMParams = (\n url: string,\n utmParams: Record<string, string>,\n): string => {\n if (!url) return \"\";\n try {\n const newURL = new URL(url);\n for (const [key, value] of Object.entries(utmParams)) {\n if (value === \"\") {\n newURL.searchParams.delete(key);\n } else {\n newURL.searchParams.set(key, value.replace(/\\+/g, \" \"));\n }\n }\n return newURL.toString();\n } catch (_) {\n return \"\";\n }\n};\n\n/**\n * Removes all UTM parameters from a URL\n * Useful for cleaning URLs before sharing or storing\n *\n * @param url - The URL to remove UTM parameters from\n * @returns The URL without any UTM parameters\n *\n * @example\n * ```typescript\n * import { getUrlWithoutUTMParams } from '@kumix/utils';\n *\n * // Remove UTM parameters\n * getUrlWithoutUTMParams('https://example.com?utm_source=twitter&utm_medium=social&page=2');\n * // Returns \"https://example.com?page=2\"\n *\n * // URL without UTM parameters (unchanged)\n * getUrlWithoutUTMParams('https://example.com?page=2&category=shoes');\n * // Returns \"https://example.com?page=2&category=shoes\"\n *\n * // With invalid URL\n * getUrlWithoutUTMParams('not-a-url');\n * // Returns \"not-a-url\" (unchanged)\n *\n * // Use for clean sharing URLs\n * const shareUrl = getUrlWithoutUTMParams(window.location.href);\n * navigator.share({ url: shareUrl });\n *\n * // Use for canonical URLs\n * const canonicalUrl = getUrlWithoutUTMParams(currentUrl);\n * document.querySelector('link[rel=\"canonical\"]').href = canonicalUrl;\n *\n * // Use in analytics to group by clean URL\n * const cleanUrl = getUrlWithoutUTMParams(pageUrl);\n * analytics.track('page_view', { clean_url: cleanUrl });\n * ```\n */\nexport const getUrlWithoutUTMParams = (url: string): string => {\n try {\n const newURL = new URL(url);\n // Strip every recognized UTM/ref tag. Iterate UTMTags directly so adding a\n // new tag in one place automatically extends the strip list.\n for (const key of UTMTags) {\n newURL.searchParams.delete(key);\n }\n return newURL.toString();\n } catch (_) {\n return url;\n }\n};\n\n/**\n * Creates a URL with optional UTM parameters for a specific domain\n * Useful for generating links with tracking parameters\n *\n * @param href - The base URL or path\n * @param domain - The domain to check against\n * @param utmParams - Optional UTM parameters to add to the URL\n * @returns A formatted URL with UTM parameters if applicable\n *\n * @example\n * ```typescript\n * import { createHref, UTMTags } from '@kumix/utils';\n *\n * // Basic usage\n * createHref('/features', 'example.com');\n * // Returns \"https://domain.com/features\" (with domain transformation)\n *\n * // With UTM parameters\n * createHref('/features', 'example.com', {\n * utm_source: 'twitter',\n * utm_medium: 'social'\n * });\n * // Returns \"https://domain.com/features?utm_source=twitter&utm_medium=social\"\n *\n * // With special domain case\n * createHref('/features', 'domain.com');\n * // Returns \"/features\" (unchanged)\n *\n * // With absolute URL\n * createHref('https://example.com/page', 'example.com');\n * // Returns \"https://example.com/page\"\n *\n * // Use in navigation components\n * const navLinks = [\n * { href: createHref('/pricing', domain, { utm_source: 'nav' }), label: 'Pricing' },\n * { href: createHref('/features', domain, { utm_source: 'nav' }), label: 'Features' }\n * ];\n * ```\n */\nexport const createHref = (\n href: string,\n domain: string,\n // any params, doesn't have to be all of them\n utmParams?: Partial<Record<(typeof UTMTags)[number], string>>,\n): string => {\n // Normalize the domain so we can always feed a valid absolute URL into the\n // URL constructor. Accepts inputs like \"example.com\", \"https://example.com\",\n // or \"https://example.com/\" without throwing.\n const hasScheme = /^[a-zA-Z][a-zA-Z0-9+.-]*:\\/\\//.test(domain);\n const base = hasScheme ? domain : `https://${domain}`;\n const normalizedBase = base.endsWith(\"/\") ? base.slice(0, -1) : base;\n const path = href.startsWith(\"/\") ? href : `/${href}`;\n\n let url: URL;\n try {\n url = new URL(`${normalizedBase}${path}`);\n } catch (_) {\n return \"\";\n }\n\n if (utmParams) {\n Object.entries(utmParams).forEach(([key, value]) => {\n if (typeof value === \"string\" && value.length > 0) {\n url.searchParams.set(key, value);\n }\n });\n }\n return url.toString();\n};\n","/**\n * Utility function for deep object comparison\n * Provides recursive comparison of nested objects and arrays\n */\n\n/**\n * Type definition for the deepEqual function\n * Specifies the function signature for comparing two objects deeply\n */\ntype DeepEqual = (obj1: Record<string, unknown>, obj2: Record<string, unknown>) => boolean;\n\n/**\n * Performs a deep equality check between two objects\n * Recursively compares all nested properties and values\n *\n * @param obj1 - First object to compare\n * @param obj2 - Second object to compare\n * @returns True if objects are deeply equal, false otherwise\n *\n * @example\n * ```ts\n * import { deepEqual } from '@/utils/functions';\n *\n * // Simple objects\n * deepEqual({ a: 1, b: 2 }, { a: 1, b: 2 })\n * // Returns true\n *\n * // Different order of keys doesn't matter\n * deepEqual({ a: 1, b: 2 }, { b: 2, a: 1 })\n * // Returns true\n *\n * // Nested objects\n * deepEqual(\n * { a: 1, b: { c: 3, d: 4 } },\n * { a: 1, b: { c: 3, d: 4 } }\n * )\n * // Returns true\n *\n * // Different values\n * deepEqual({ a: 1, b: 2 }, { a: 1, b: 3 })\n * // Returns false\n *\n * // Different structure\n * deepEqual({ a: 1, b: 2 }, { a: 1, c: 2 })\n * // Returns false\n *\n * // Different nesting\n * deepEqual(\n * { a: 1, b: { c: 3 } },\n * { a: 1, b: { c: 4 } }\n * )\n * // Returns false\n * ```\n */\nexport const deepEqual: DeepEqual = (obj1, obj2) => {\n if (obj1 === obj2) {\n return true;\n }\n\n if (typeof obj1 !== \"object\" || typeof obj2 !== \"object\" || obj1 === null || obj2 === null) {\n return false;\n }\n\n // Compare by type tag to distinguish Date, RegExp, Map, Set, Array, etc.\n const tag1 = Object.prototype.toString.call(obj1);\n const tag2 = Object.prototype.toString.call(obj2);\n if (tag1 !== tag2) {\n return false;\n }\n\n // Handle Date — compare by time value\n if (obj1 instanceof Date && obj2 instanceof Date) {\n return obj1.getTime() === obj2.getTime();\n }\n\n // Handle RegExp — compare source and flags\n if (obj1 instanceof RegExp && obj2 instanceof RegExp) {\n return obj1.source === obj2.source && obj1.flags === obj2.flags;\n }\n\n // Handle arrays — compare length first, then elements in order\n if (Array.isArray(obj1) && Array.isArray(obj2)) {\n if (obj1.length !== obj2.length) {\n return false;\n }\n for (let i = 0; i < obj1.length; i++) {\n if (!deepEqual(obj1[i] as Record<string, unknown>, obj2[i] as Record<string, unknown>)) {\n return false;\n }\n }\n return true;\n }\n\n // Handle Map — compare size, then every key/value pair (order-sensitive, like array)\n if (obj1 instanceof Map && obj2 instanceof Map) {\n if (obj1.size !== obj2.size) {\n return false;\n }\n for (const [key, value] of obj1) {\n if (!obj2.has(key)) {\n return false;\n }\n if (!deepEqual(value as Record<string, unknown>, obj2.get(key) as Record<string, unknown>)) {\n return false;\n }\n }\n return true;\n }\n\n // Handle Set — compare size, then every element (deepEqual to support object members)\n if (obj1 instanceof Set && obj2 instanceof Set) {\n if (obj1.size !== obj2.size) {\n return false;\n }\n for (const value of obj1) {\n // Sets don't have deep lookup, so check each candidate of obj2.\n let found = false;\n for (const other of obj2) {\n if (deepEqual(value as Record<string, unknown>, other as Record<string, unknown>)) {\n found = true;\n break;\n }\n }\n if (!found) {\n return false;\n }\n }\n return true;\n }\n\n const keys1 = Object.keys(obj1);\n const keys2 = Object.keys(obj2);\n\n if (keys1.length !== keys2.length) {\n return false;\n }\n\n for (const key of keys1) {\n if (!keys2.includes(key)) {\n return false;\n }\n\n const val1 = obj1[key];\n const val2 = obj2[key];\n\n // If both values are objects, recursively compare them\n if (typeof val1 === \"object\" && val1 !== null && typeof val2 === \"object\" && val2 !== null) {\n if (!deepEqual(val1 as Record<string, unknown>, val2 as Record<string, unknown>)) {\n return false;\n }\n } else if (val1 !== val2) {\n // For non-object values, use strict equality\n return false;\n }\n }\n\n return true;\n};\n","/**\n * Email validation and formatting utilities for SaaS applications\n * Provides comprehensive email validation, normalization, and domain checking\n * Includes support for disposable email detection and business email validation\n */\n\n/**\n * Interface for email validation result\n */\ninterface EmailValidationResult {\n /** Whether the email is valid */\n isValid: boolean;\n /** Normalized email address */\n normalized?: string;\n /** Error message if validation failed */\n error?: string;\n /** Additional validation details */\n details?: {\n /** Whether the domain appears to be disposable */\n isDisposable?: boolean;\n /** Whether the email appears to be a business email */\n isBusiness?: boolean;\n /** The domain part of the email */\n domain?: string;\n };\n}\n\n/**\n * Common disposable email domains\n * Used to detect temporary/throwaway email addresses\n */\nconst DISPOSABLE_EMAIL_DOMAINS = new Set([\n \"10minutemail.com\",\n \"guerrillamail.com\",\n \"mailinator.com\",\n \"tempmail.org\",\n \"yopmail.com\",\n \"temp-mail.org\",\n \"throwaway.email\",\n \"getnada.com\",\n \"maildrop.cc\",\n \"sharklasers.com\",\n \"guerrillamailblock.com\",\n \"pokemail.net\",\n \"spam4.me\",\n \"bccto.me\",\n \"chacuo.net\",\n \"dispostable.com\",\n \"fakeinbox.com\",\n \"hide.biz.st\",\n \"mytrashmail.com\",\n \"nobulk.com\",\n \"sogetthis.com\",\n \"spamherelots.com\",\n \"spamhereplease.com\",\n \"spamthisplease.com\",\n \"superrito.com\",\n \"tempemail.com\",\n \"thankyou2010.com\",\n \"trash2009.com\",\n \"trashymail.com\",\n \"tyldd.com\",\n]);\n\n/**\n * Free email providers\n * Used to distinguish between free and business email addresses\n */\nconst FREE_EMAIL_DOMAINS = new Set([\n \"gmail.com\",\n \"yahoo.com\",\n \"hotmail.com\",\n \"outlook.com\",\n \"aol.com\",\n \"icloud.com\",\n \"protonmail.com\",\n \"mail.com\",\n \"yandex.com\",\n \"zoho.com\",\n \"fastmail.com\",\n \"tutanota.com\",\n]);\n\n/**\n * Validates an email address with comprehensive checks\n *\n * @param email - The email address to validate\n * @param options - Validation options\n * @returns Validation result with details\n *\n * @example\n * ```typescript\n * import { validateEmail } from '@kumix/utils';\n *\n * // Basic validation\n * const result = validateEmail('user@example.com');\n * if (result.isValid) {\n * console.log('Valid email:', result.normalized);\n * }\n *\n * // Check for disposable emails\n * const result = validateEmail('test@10minutemail.com');\n * if (result.details?.isDisposable) {\n * throw new Error('Disposable emails are not allowed');\n * }\n *\n * // Business email validation\n * const result = validateEmail('john@company.com');\n * if (result.details?.isBusiness) {\n * // Apply business-specific logic\n * await createBusinessAccount(result.normalized);\n * }\n *\n * // In user registration\n * async function registerUser(email: string, password: string) {\n * const emailResult = validateEmail(email);\n * if (!emailResult.isValid) {\n * throw new Error(emailResult.error || 'Invalid email');\n * }\n *\n * if (emailResult.details?.isDisposable) {\n * throw new Error('Please use a permanent email address');\n * }\n *\n * await createUser({\n * email: emailResult.normalized,\n * password: await hashPassword(password)\n * });\n * }\n * ```\n */\nexport function validateEmail(\n email: string,\n options: {\n /** Whether to allow disposable emails (default: true) */\n allowDisposable?: boolean;\n /** Whether to require business emails (default: false) */\n requireBusiness?: boolean;\n } = {},\n): EmailValidationResult {\n const { allowDisposable = true, requireBusiness = false } = options;\n\n // Basic validation\n if (!email || typeof email !== \"string\") {\n return {\n isValid: false,\n error: \"Email must be a non-empty string\",\n };\n }\n\n const trimmedEmail = email.trim().toLowerCase();\n\n if (trimmedEmail.length === 0) {\n return {\n isValid: false,\n error: \"Email cannot be empty\",\n };\n }\n\n // RFC 5322 compliant email regex (simplified but robust)\n const emailRegex =\n /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;\n\n if (!emailRegex.test(trimmedEmail)) {\n return {\n isValid: false,\n error: \"Invalid email format\",\n };\n }\n\n // Extract domain\n const domain = trimmedEmail.split(\"@\")[1];\n if (!domain) {\n return {\n isValid: false,\n error: \"Invalid email format - missing domain\",\n };\n }\n\n // Check for disposable email\n const isDisposable = DISPOSABLE_EMAIL_DOMAINS.has(domain);\n if (!allowDisposable && isDisposable) {\n return {\n isValid: false,\n error: \"Disposable email addresses are not allowed\",\n details: { isDisposable: true, domain },\n };\n }\n\n // Check for business email\n const isFreeEmail = FREE_EMAIL_DOMAINS.has(domain);\n const isBusiness = !isFreeEmail && !isDisposable;\n\n if (requireBusiness && !isBusiness) {\n return {\n isValid: false,\n error: \"Business email address is required\",\n details: { isBusiness: false, domain },\n };\n }\n\n return {\n isValid: true,\n normalized: trimmedEmail,\n details: {\n isDisposable,\n isBusiness,\n domain,\n },\n };\n}\n\n/**\n * Normalizes an email address for consistent storage and comparison\n *\n * @param email - The email address to normalize\n * @returns Normalized email address or null if invalid\n *\n * @example\n * ```typescript\n * import { normalizeEmail } from '@kumix/utils';\n *\n * // Basic normalization\n * const normalized = normalizeEmail(' USER@EXAMPLE.COM ');\n * // Returns: 'user@example.com'\n *\n * // Gmail-specific normalization\n * const normalized = normalizeEmail('user.name+tag@gmail.com');\n * // Returns: 'username@gmail.com'\n *\n * // In user lookup\n * async function findUserByEmail(email: string) {\n * const normalizedEmail = normalizeEmail(email);\n * if (!normalizedEmail) {\n * throw new Error('Invalid email format');\n * }\n *\n * return await User.findOne({ email: normalizedEmail });\n * }\n * ```\n */\nexport function normalizeEmail(email: string): string | null {\n const result = validateEmail(email);\n if (!result.isValid || !result.normalized) {\n return null;\n }\n\n let normalized = result.normalized;\n const [localPart, domain] = normalized.split(\"@\");\n\n // Gmail-specific normalization\n if (domain === \"gmail.com\") {\n // Remove dots and everything after +\n const cleanLocal = localPart.replace(/\\./g, \"\").split(\"+\")[0];\n normalized = `${cleanLocal}@${domain}`;\n }\n\n // Outlook/Hotmail-specific normalization\n if ([\"outlook.com\", \"hotmail.com\", \"live.com\"].includes(domain)) {\n // Remove everything after +\n const cleanLocal = localPart.split(\"+\")[0];\n normalized = `${cleanLocal}@${domain}`;\n }\n\n return normalized;\n}\n\n/**\n * Checks if an email domain is disposable/temporary\n *\n * @param email - The email address to check\n * @returns True if the domain is disposable\n *\n * @example\n * ```typescript\n * import { isDisposableEmail } from '@kumix/utils';\n *\n * // Check for disposable email\n * if (isDisposableEmail('test@10minutemail.com')) {\n * throw new Error('Please use a permanent email address');\n * }\n *\n * // In email validation middleware\n * function validateUserEmail(email: string) {\n * if (isDisposableEmail(email)) {\n * return {\n * valid: false,\n * error: 'Temporary email addresses are not allowed'\n * };\n * }\n * return { valid: true };\n * }\n * ```\n */\nexport function isDisposableEmail(email: string): boolean {\n const result = validateEmail(email);\n return result.details?.isDisposable || false;\n}\n\n/**\n * Checks if an email appears to be a business email\n *\n * @param email - The email address to check\n * @returns True if the email appears to be business-related\n *\n * @example\n * ```typescript\n * import { isBusinessEmail } from '@kumix/utils';\n *\n * // Check for business email\n * if (isBusinessEmail('john@company.com')) {\n * // Apply business account features\n * await enableBusinessFeatures(user);\n * }\n *\n * // In pricing logic\n * function getAccountType(email: string) {\n * return isBusinessEmail(email) ? 'business' : 'personal';\n * }\n * ```\n */\nexport function isBusinessEmail(email: string): boolean {\n const result = validateEmail(email);\n return result.details?.isBusiness || false;\n}\n\n/**\n * Extracts the domain from an email address\n *\n * @param email - The email address\n * @returns The domain part or null if invalid\n *\n * @example\n * ```typescript\n * import { getEmailDomain } from '@kumix/utils';\n *\n * // Extract domain\n * const domain = getEmailDomain('user@example.com');\n * // Returns: 'example.com'\n *\n * // Domain-based logic\n * function getCompanyFromEmail(email: string) {\n * const domain = getEmailDomain(email);\n * if (domain) {\n * return domain.split('.')[0]; // 'example' from 'example.com'\n * }\n * return null;\n * }\n * ```\n */\nexport function getEmailDomain(email: string): string | null {\n const result = validateEmail(email);\n return result.details?.domain || null;\n}\n","/**\n * Utility function for iframe embedding validation\n * Checks if a URL can be embedded in an iframe based on security headers\n */\n\n/**\n * Determines if a URL can be displayed in an iframe by checking security headers.\n * Examines Content-Security-Policy `frame-ancestors` and `X-Frame-Options` headers.\n *\n * A URL is considered embeddable only when:\n * - `frame-ancestors` is absent OR explicitly allows `*` / `self` (same origin) /\n * a wildcard/origin that matches `requestDomain`, AND\n * - `X-Frame-Options` is not `DENY` or `SAMEORIGIN` (when origin differs).\n *\n * @param options - The options for the check\n * @param options.url - The URL to check for iframe embedding capability\n * @param options.requestDomain - The origin that will be embedding the iframe\n * (e.g. `https://myapp.com`). Compared against CSP source expressions.\n * @returns A Promise that resolves to true if the URL can be embedded, false otherwise.\n *\n * @example\n * ```ts\n * import { isIframeable } from '@/utils/functions';\n *\n * const canEmbed = await isIframeable({\n * url: 'https://example.com',\n * requestDomain: 'https://myapp.com'\n * });\n * ```\n */\nexport const isIframeable = async ({\n url,\n requestDomain,\n}: {\n url: string;\n requestDomain: string;\n}): Promise<boolean> => {\n const res = await fetch(url);\n\n const normalizeOrigin = (value: string) => value.trim().replace(/\\/$/, \"\").toLowerCase();\n const requestedOrigin = normalizeOrigin(requestDomain);\n\n // 1. Content-Security-Policy: frame-ancestors (CSP Level 2).\n // If present, it is the authoritative source for embeddability — it OVERRIDES\n // X-Frame-Options per the CSP spec.\n const cspHeader = res.headers.get(\"content-security-policy\");\n if (cspHeader) {\n const frameAncestorsMatch = cspHeader.match(/frame-ancestors\\s+([\\s\\S]+?)(?=;|$)/i);\n if (frameAncestorsMatch) {\n const sources = frameAncestorsMatch[1].trim().split(/\\s+/).filter(Boolean);\n\n const isAllowed = sources.some((source) => {\n const s = source.toLowerCase();\n if (s === \"'none'\") return false;\n if (s === \"*\" || s === \"https:*\" || s === \"http:*\") return true;\n if (s === \"'self'\") {\n // 'self' means same origin as the framed document, not the embedder.\n // We can't reliably know the embedder matches without comparing to the\n // response URL's origin, so treat conservatively as a match only when\n // the request domain matches the target URL origin.\n try {\n const targetOrigin = normalizeOrigin(new URL(res.url).origin);\n return targetOrigin === requestedOrigin;\n } catch {\n return false;\n }\n }\n // Wildcard scheme/host like https://*.example.com\n if (s.includes(\"*\")) {\n const pattern = s.replace(/[.+?^${}()|[\\]\\\\]/g, \"\\\\$&\").replace(/\\*/g, \".*\");\n return new RegExp(`^${pattern}$`).test(requestedOrigin);\n }\n return normalizeOrigin(s) === requestedOrigin;\n });\n\n // frame-ancestors is authoritative: if it doesn't list us, we are blocked,\n // regardless of X-Frame-Options.\n return isAllowed;\n }\n }\n\n // 2. X-Frame-Options (legacy, CVE-prone). Only consulted when no frame-ancestors.\n const xFrameOptions = res.headers.get(\"X-Frame-Options\");\n if (xFrameOptions) {\n const value = xFrameOptions.trim().toUpperCase();\n if (value === \"DENY\") {\n return false;\n }\n if (value === \"SAMEORIGIN\") {\n try {\n return normalizeOrigin(new URL(res.url).origin) === requestedOrigin;\n } catch {\n return false;\n }\n }\n // \"ALLOW-FROM\" is deprecated and unsupported; treat as not embeddable.\n if (value.startsWith(\"ALLOW-FROM\")) {\n return false;\n }\n }\n\n return true;\n};\n","/**\n * Utility functions for key validation and management\n * Provides tools for validating and checking special keys in the system\n */\n\n/**\n * Regular expression for validating keys\n * Allows letters, numbers, '-', '_', '/', '.', and emojis\n *\n * @example\n * ```ts\n * import { validKeyRegex } from '@/utils/functions';\n *\n * // Check if a key is valid\n * const isValidKey = (key: string) => validKeyRegex.test(key);\n *\n * isValidKey('user-profile') // true\n * isValidKey('path/to/resource') // true\n * isValidKey('emoji-😊-key') // true\n * isValidKey('<invalid>') // false\n * ```\n */\nexport const validKeyRegex = new RegExp(/^[0-9A-Za-z_\\u0080-\\uFFFF/\\p{Emoji}.-]+$/u);\n\n/**\n * Checks if a key is unsupported by the system\n * Validates against excluded prefixes and suffixes\n * Special case for '_root' which is always supported\n *\n * @param key - The key to check\n * @returns True if the key is unsupported, false otherwise\n *\n * @example\n * ```ts\n * import { isUnsupportedKey } from '@/utils/functions';\n *\n * isUnsupportedKey('normal-key') // false\n * isUnsupportedKey('_root') // false (special case)\n * isUnsupportedKey('.well-known/acme-challenge') // true\n * isUnsupportedKey('script.php') // true\n * ```\n */\nexport const isUnsupportedKey = (key: string): boolean => {\n // special case for root domain links\n if (key === \"_root\") {\n return false;\n }\n const excludedPrefix = [\".well-known\"];\n const excludedSuffix = [\".php\", \".php7\"];\n return (\n excludedPrefix.some((prefix) => key.startsWith(prefix)) ||\n excludedSuffix.some((suffix) => key.endsWith(suffix))\n );\n};\n\n/**\n * Checks if a key is globally reserved by the system\n * These keys are reserved for special system files and cannot be used by users\n *\n * @param key - The key to check\n * @returns True if the key is globally reserved, false otherwise\n *\n * @example\n * ```ts\n * import { isReservedKeyGlobal } from '@/utils/functions';\n *\n * isReservedKeyGlobal('favicon.ico') // true\n * isReservedKeyGlobal('robots.txt') // true\n * isReservedKeyGlobal('custom-page') // false\n *\n * // Validate user input\n * function validateUserKey(key: string) {\n * if (isReservedKeyGlobal(key)) {\n * return 'This key is reserved for system use';\n * }\n * return null; // Valid\n * }\n * ```\n */\nexport const isReservedKeyGlobal = (key: string): boolean => {\n const reservedKeys = [\n \"favicon.ico\",\n \"sitemap.xml\",\n \"robots.txt\",\n \"manifest.webmanifest\",\n \"manifest.json\",\n \"apple-app-site-association\",\n ];\n return reservedKeys.includes(key);\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAiCA,MAAa,8BAA8B;CACzC;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC/HA,MAAa,aAAwC;CACnD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;;;;;;;;;;;;;;;;;;;;AAqBA,MAAa,kBAAkB,OAAO,KAAK,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC7BrD,MAAa,YAAuC;CAClD,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AACN;;;;;;;;;;;;;;;;;;;;;;;;;AA0BA,MAAa,gBAAgB,OAAO,KAAK,SAAS;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAgClD,MAAa,mBAAmB;CAC9B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC5UA,MAAa,sBAAiD;CAC5D,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;CACJ,IAAI;AAON;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;ACpPA,MAAa,UAAqC;CAChD,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,UAAU;CACV,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,UAAU;CACV,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,QAAQ;CACR,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;CACT,SAAS;AACX;AAEA,MAAa,eAAe,OAAO,KAAK,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;AC16G/C,MAAa,yBAAS,IAAI,IAAI;CAC5B;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA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"}