{"id":68,"date":"2026-08-22T23:54:37","date_gmt":"2026-08-22T14:54:37","guid":{"rendered":"https:\/\/haibara.us\/?p=68"},"modified":"2026-08-23T00:32:20","modified_gmt":"2026-08-22T15:32:20","slug":"oracle-cloud-global-regions-map-test-ips","status":"publish","type":"post","link":"https:\/\/haibara.us\/?p=68","title":{"rendered":"Oracle Cloud Global Regions Map &amp; Test IPs"},"content":{"rendered":"\n<!--\n=============================================================================\nOCI GLOBAL REGION OBSERVATORY \u2014 EMBED-SAFE VERSION\n-----------------------------------------------------------------------------\nDesigned to be pasted inside an existing blog\/article page.\n\nFixes compared with the previous version:\n1) All visual CSS is scoped under #oci-region-app, so it will NOT modify\n   your blog sidebar, recommended posts, global h1\/p\/content styles, etc.\n2) Leaflet tile images are protected from common WordPress\/theme img rules.\n3) Responsive layout uses a CSS CONTAINER QUERY based on the article width.\n4) OCI regional endpoint IPs are resolved live with DNS-over-HTTPS.\n5) You can still override any region with your own test-server IP below.\n=============================================================================\n-->\n\n<div id=\"oci-region-app\">\n  <div class=\"ociw-frame\">\n\n    <header class=\"ociw-header\">\n      <div class=\"ociw-brand\">\n        <span class=\"ociw-oracle-mark\" aria-hidden=\"true\"><\/span>\n        <div>\n          <div class=\"ociw-brand-title\">Oracle Cloud Infrastructure<\/div>\n          <div class=\"ociw-brand-sub\">Global Region Observatory<\/div>\n        <\/div>\n      <\/div>\n\n      <div class=\"ociw-live\">\n        <span class=\"ociw-live-dot\"><\/span>\n        INTERACTIVE MAP ONLINE\n      <\/div>\n    <\/header>\n\n    <section class=\"ociw-intro\">\n      <div>\n        <div class=\"ociw-kicker\">OCI \/ COMMERCIAL CLOUD REGIONS<\/div>\n        <h2 class=\"ociw-title\">\n          Global infrastructure,\n          <span>one map.<\/span>\n        <\/h2>\n        <p class=\"ociw-copy\">\n          Hover over any region to see its OCI identifier, region key,\n          Availability Domain count, regional test endpoint and resolved IP.\n        <\/p>\n      <\/div>\n\n      <div class=\"ociw-stats\">\n        <div class=\"ociw-stat\">\n          <span>REGIONS<\/span>\n          <strong id=\"ociw-region-count\">45<\/strong>\n        <\/div>\n        <div class=\"ociw-stat\">\n          <span>AVAILABILITY DOMAINS<\/span>\n          <strong id=\"ociw-ad-count\">55<\/strong>\n        <\/div>\n        <div class=\"ociw-stat\">\n          <span>RESOLVED IPS<\/span>\n          <strong><b id=\"ociw-ip-count\">0<\/b><small> \/ 45<\/small><\/strong>\n        <\/div>\n        <div class=\"ociw-stat\">\n          <span>REALMS<\/span>\n          <strong class=\"ociw-realm-stat\">OC1 <small>+ OC20<\/small><\/strong>\n        <\/div>\n      <\/div>\n    <\/section>\n\n    <div class=\"ociw-toolbar\">\n      <label class=\"ociw-search-wrap\">\n        <span aria-hidden=\"true\">\u2315<\/span>\n        <input\n          id=\"ociw-search\"\n          class=\"ociw-search\"\n          type=\"search\"\n          placeholder=\"Search region, city, country or code...\"\n          autocomplete=\"off\"\n        \/>\n      <\/label>\n\n      <div class=\"ociw-filters\" aria-label=\"Region filters\">\n        <button type=\"button\" class=\"ociw-filter is-active\" data-filter=\"all\">All<\/button>\n        <button type=\"button\" class=\"ociw-filter\" data-filter=\"americas\">Americas<\/button>\n        <button type=\"button\" class=\"ociw-filter\" data-filter=\"europe\">Europe<\/button>\n        <button type=\"button\" class=\"ociw-filter\" data-filter=\"apac\">APAC<\/button>\n        <button type=\"button\" class=\"ociw-filter\" data-filter=\"mea\">ME &#038; Africa<\/button>\n      <\/div>\n    <\/div>\n\n    <section class=\"ociw-layout\">\n      <div class=\"ociw-map-card\">\n        <div id=\"ociw-map\" class=\"ociw-map\" aria-label=\"Oracle Cloud region map\"><\/div>\n\n        <div class=\"ociw-map-note\">\n          <strong>LIVE ENDPOINT RESOLUTION<\/strong>\n          <span>\n            IPs are resolved from OCI regional service endpoints and may change.\n            Your own test IPs can override them in <code>CUSTOM_TEST_IPS<\/code>.\n          <\/span>\n        <\/div>\n      <\/div>\n\n      <aside class=\"ociw-region-card\">\n        <div class=\"ociw-region-head\">\n          <div>\n            <strong>Oracle Cloud Regions<\/strong>\n            <span id=\"ociw-list-meta\">45 regions visible<\/span>\n          <\/div>\n          <div class=\"ociw-resolve-state\" id=\"ociw-resolve-state\">DNS queue starting\u2026<\/div>\n        <\/div>\n\n        <div id=\"ociw-region-list\" class=\"ociw-region-list\"><\/div>\n      <\/aside>\n    <\/section>\n\n    <footer class=\"ociw-footer\">\n      <span>OCI GLOBAL INFRASTRUCTURE<\/span>\n      <span>Hover a node \u2192 view endpoint IP<\/span>\n    <\/footer>\n  <\/div>\n<\/div>\n\n<style>\n\/* --------------------------------------------------------------------------\n   IMPORTANT: every selector is scoped to #oci-region-app.\n   Nothing here should affect the surrounding blog\/theme.\n   -------------------------------------------------------------------------- *\/\n\n#oci-region-app {\n  --ociw-bg: #070b11;\n  --ociw-panel: #0b121d;\n  --ociw-panel-2: #101925;\n  --ociw-text: #edf4ff;\n  --ociw-muted: #8795aa;\n  --ociw-muted-2: #58677b;\n  --ociw-line: rgba(255,255,255,.085);\n  --ociw-blue: #4c93ff;\n  --ociw-cyan: #5be5ff;\n  --ociw-green: #5af0a7;\n  --ociw-orange: #ff6b54;\n\n  width: 100%;\n  max-width: 100%;\n  margin: 22px 0;\n  padding: 0;\n  color: var(--ociw-text);\n  font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\n  line-height: 1.5;\n  text-align: left;\n  isolation: isolate;\n  container-type: inline-size;\n  container-name: ociRegionWidget;\n}\n\n#oci-region-app,\n#oci-region-app * {\n  box-sizing: border-box;\n}\n\n#oci-region-app button,\n#oci-region-app input {\n  font: inherit;\n}\n\n#oci-region-app .ociw-frame {\n  position: relative;\n  width: 100%;\n  max-width: 100%;\n  overflow: hidden;\n  padding: 22px;\n  border: 1px solid var(--ociw-line);\n  border-radius: 22px;\n  background:\n    radial-gradient(circle at 18% 0%, rgba(76,147,255,.13), transparent 27rem),\n    radial-gradient(circle at 100% 12%, rgba(91,229,255,.07), transparent 25rem),\n    #070b11;\n  box-shadow: 0 24px 70px rgba(0,0,0,.28);\n}\n\n#oci-region-app .ociw-frame::before {\n  content: \"\";\n  position: absolute;\n  inset: 0;\n  z-index: 0;\n  pointer-events: none;\n  opacity: .25;\n  background-image:\n    linear-gradient(rgba(255,255,255,.023) 1px, transparent 1px),\n    linear-gradient(90deg, rgba(255,255,255,.023) 1px, transparent 1px);\n  background-size: 42px 42px;\n  mask-image: linear-gradient(to bottom, #000 0%, transparent 72%);\n}\n\n#oci-region-app .ociw-frame > * {\n  position: relative;\n  z-index: 1;\n}\n\n#oci-region-app .ociw-header {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 16px;\n  margin: 0 0 18px;\n  padding: 0 2px;\n}\n\n#oci-region-app .ociw-brand {\n  min-width: 0;\n  display: flex;\n  align-items: center;\n  gap: 11px;\n}\n\n#oci-region-app .ociw-oracle-mark {\n  flex: 0 0 auto;\n  width: 42px;\n  height: 42px;\n  display: grid;\n  place-items: center;\n  border: 1px solid rgba(255,255,255,.12);\n  border-radius: 13px;\n  background: rgba(255,255,255,.035);\n}\n\n#oci-region-app .ociw-oracle-mark::before {\n  content: \"\";\n  width: 24px;\n  height: 11px;\n  border: 3px solid var(--ociw-orange);\n  border-radius: 999px;\n  box-shadow: 0 0 16px rgba(255,107,84,.22);\n}\n\n#oci-region-app .ociw-brand-title {\n  margin: 0;\n  color: #f3f7ff;\n  font-size: 15px;\n  line-height: 1.3;\n  font-weight: 720;\n  letter-spacing: -.02em;\n}\n\n#oci-region-app .ociw-brand-sub {\n  margin-top: 3px;\n  color: #6f85a4;\n  font: 10px\/1.4 \"SFMono-Regular\", Consolas, monospace;\n  letter-spacing: .12em;\n  text-transform: uppercase;\n}\n\n#oci-region-app .ociw-live {\n  flex: 0 0 auto;\n  display: inline-flex;\n  align-items: center;\n  gap: 8px;\n  color: #9aaac0;\n  font: 10px\/1 \"SFMono-Regular\", Consolas, monospace;\n  letter-spacing: .10em;\n}\n\n#oci-region-app .ociw-live-dot {\n  width: 7px;\n  height: 7px;\n  border-radius: 50%;\n  background: var(--ociw-green);\n  box-shadow: 0 0 14px rgba(90,240,167,.8);\n}\n\n#oci-region-app .ociw-intro {\n  display: grid;\n  grid-template-columns: minmax(0, 1.25fr) minmax(300px, .75fr);\n  gap: 14px;\n  margin-bottom: 14px;\n}\n\n#oci-region-app .ociw-intro > div:first-child {\n  min-width: 0;\n  padding: 27px 28px;\n  border: 1px solid var(--ociw-line);\n  border-radius: 18px;\n  background: linear-gradient(145deg, rgba(17,28,44,.93), rgba(8,13,21,.91));\n}\n\n#oci-region-app .ociw-kicker {\n  margin: 0 0 14px;\n  color: #8eb8ff;\n  font: 10px\/1.3 \"SFMono-Regular\", Consolas, monospace;\n  letter-spacing: .12em;\n}\n\n#oci-region-app .ociw-title {\n  margin: 0 !important;\n  padding: 0 !important;\n  border: 0 !important;\n  background: none !important;\n  color: #f6f9ff !important;\n  font-family: inherit !important;\n  font-size: clamp(30px, 5cqi, 53px) !important;\n  font-weight: 760 !important;\n  line-height: 1.01 !important;\n  letter-spacing: -.055em !important;\n  text-transform: none !important;\n}\n\n#oci-region-app .ociw-title span {\n  color: transparent;\n  background: linear-gradient(100deg, #ffffff, #9cc4ff 48%, #63e7fb);\n  -webkit-background-clip: text;\n  background-clip: text;\n}\n\n#oci-region-app .ociw-copy {\n  max-width: 650px;\n  margin: 17px 0 0 !important;\n  padding: 0 !important;\n  color: var(--ociw-muted) !important;\n  font-family: inherit !important;\n  font-size: 13px !important;\n  line-height: 1.75 !important;\n}\n\n#oci-region-app .ociw-stats {\n  display: grid;\n  grid-template-columns: 1fr 1fr;\n  gap: 1px;\n  overflow: hidden;\n  border: 1px solid var(--ociw-line);\n  border-radius: 18px;\n  background: var(--ociw-line);\n}\n\n#oci-region-app .ociw-stat {\n  min-width: 0;\n  min-height: 98px;\n  padding: 16px;\n  background: rgba(9,15,24,.96);\n}\n\n#oci-region-app .ociw-stat > span {\n  display: block;\n  margin: 0 0 10px;\n  color: var(--ociw-muted-2);\n  font: 9px\/1.35 \"SFMono-Regular\", Consolas, monospace;\n  letter-spacing: .08em;\n}\n\n#oci-region-app .ociw-stat > strong {\n  display: block;\n  margin: 0;\n  color: #edf4ff;\n  font-size: 29px;\n  font-weight: 750;\n  line-height: 1;\n  letter-spacing: -.045em;\n}\n\n#oci-region-app .ociw-stat > strong small {\n  color: #8b9bb0;\n  font-size: 11px;\n  font-weight: 500;\n  letter-spacing: 0;\n}\n\n#oci-region-app .ociw-stat .ociw-realm-stat {\n  font-size: 24px;\n}\n\n#oci-region-app .ociw-toolbar {\n  display: flex;\n  align-items: center;\n  gap: 9px;\n  min-width: 0;\n  margin: 0 0 12px;\n}\n\n#oci-region-app .ociw-search-wrap {\n  position: relative;\n  flex: 1 1 320px;\n  min-width: 180px;\n  margin: 0;\n}\n\n#oci-region-app .ociw-search-wrap > span {\n  position: absolute;\n  left: 14px;\n  top: 50%;\n  transform: translateY(-50%);\n  color: var(--ociw-muted-2);\n  font-size: 14px;\n  pointer-events: none;\n}\n\n#oci-region-app .ociw-search {\n  display: block;\n  width: 100% !important;\n  height: 42px !important;\n  min-height: 42px !important;\n  margin: 0 !important;\n  padding: 0 14px 0 39px !important;\n  border: 1px solid var(--ociw-line) !important;\n  border-radius: 12px !important;\n  outline: 0 !important;\n  box-shadow: none !important;\n  background: rgba(9,15,24,.94) !important;\n  color: #edf4ff !important;\n  font-family: inherit !important;\n  font-size: 12px !important;\n  line-height: 42px !important;\n}\n\n#oci-region-app .ociw-search:focus {\n  border-color: rgba(76,147,255,.55) !important;\n  box-shadow: 0 0 0 4px rgba(76,147,255,.08) !important;\n}\n\n#oci-region-app .ociw-filters {\n  display: flex;\n  align-items: center;\n  gap: 7px;\n  flex: 0 1 auto;\n  overflow-x: auto;\n  scrollbar-width: none;\n}\n\n#oci-region-app .ociw-filters::-webkit-scrollbar {\n  display: none;\n}\n\n#oci-region-app .ociw-filter {\n  appearance: none !important;\n  width: auto !important;\n  min-width: auto !important;\n  height: 42px !important;\n  margin: 0 !important;\n  padding: 0 12px !important;\n  border: 1px solid var(--ociw-line) !important;\n  border-radius: 12px !important;\n  box-shadow: none !important;\n  background: rgba(9,15,24,.94) !important;\n  color: #8393a9 !important;\n  font-size: 11px !important;\n  font-weight: 600 !important;\n  line-height: 40px !important;\n  white-space: nowrap;\n  cursor: pointer;\n}\n\n#oci-region-app .ociw-filter:hover,\n#oci-region-app .ociw-filter.is-active {\n  border-color: rgba(76,147,255,.34) !important;\n  background: rgba(76,147,255,.09) !important;\n  color: #dce9ff !important;\n}\n\n#oci-region-app .ociw-layout {\n  display: grid;\n  grid-template-columns: minmax(0, 1.55fr) minmax(285px, .45fr);\n  gap: 12px;\n  min-width: 0;\n}\n\n#oci-region-app .ociw-map-card,\n#oci-region-app .ociw-region-card {\n  min-width: 0;\n  border: 1px solid var(--ociw-line);\n  border-radius: 18px;\n  background: #090f18;\n  overflow: hidden;\n}\n\n#oci-region-app .ociw-map-card {\n  position: relative;\n  height: 570px;\n}\n\n#oci-region-app .ociw-map {\n  position: absolute;\n  inset: 0;\n  width: 100% !important;\n  height: 100% !important;\n  min-height: 100% !important;\n  background: #05090e;\n  z-index: 1;\n}\n\n#oci-region-app .ociw-map-note {\n  position: absolute;\n  z-index: 550;\n  left: 14px;\n  bottom: 14px;\n  max-width: min(420px, calc(100% - 28px));\n  padding: 11px 13px;\n  border: 1px solid rgba(255,255,255,.09);\n  border-radius: 12px;\n  background: rgba(4,8,13,.82);\n  backdrop-filter: blur(12px);\n  box-shadow: 0 12px 38px rgba(0,0,0,.25);\n  pointer-events: none;\n}\n\n#oci-region-app .ociw-map-note strong {\n  display: block;\n  margin: 0 0 4px;\n  color: #c9ddff;\n  font: 9px\/1.3 \"SFMono-Regular\", Consolas, monospace;\n  letter-spacing: .08em;\n}\n\n#oci-region-app .ociw-map-note span {\n  display: block;\n  color: #8090a6;\n  font: 9px\/1.55 \"SFMono-Regular\", Consolas, monospace;\n}\n\n#oci-region-app .ociw-map-note code {\n  padding: 1px 4px;\n  border-radius: 4px;\n  background: rgba(255,255,255,.06);\n  color: #9dc2ff;\n  font-family: inherit;\n}\n\n#oci-region-app .ociw-region-card {\n  height: 570px;\n  display: flex;\n  flex-direction: column;\n}\n\n#oci-region-app .ociw-region-head {\n  flex: 0 0 auto;\n  display: flex;\n  align-items: flex-start;\n  justify-content: space-between;\n  gap: 12px;\n  padding: 15px 15px 12px;\n  border-bottom: 1px solid var(--ociw-line);\n}\n\n#oci-region-app .ociw-region-head strong {\n  display: block;\n  color: #e5efff;\n  font-size: 12px;\n  line-height: 1.3;\n}\n\n#oci-region-app .ociw-region-head span {\n  display: block;\n  margin-top: 4px;\n  color: #607086;\n  font: 9px\/1.35 \"SFMono-Regular\", Consolas, monospace;\n}\n\n#oci-region-app .ociw-resolve-state {\n  flex: 0 0 auto;\n  color: #71839b;\n  font: 8px\/1.4 \"SFMono-Regular\", Consolas, monospace;\n  text-align: right;\n}\n\n#oci-region-app .ociw-region-list {\n  flex: 1 1 auto;\n  min-height: 0;\n  overflow: auto;\n  padding: 6px;\n  scrollbar-width: thin;\n  scrollbar-color: #27384f transparent;\n}\n\n#oci-region-app .ociw-region-row {\n  width: 100%;\n  display: grid;\n  grid-template-columns: 38px minmax(0,1fr) auto;\n  gap: 9px;\n  align-items: center;\n  margin: 0 !important;\n  padding: 9px 8px !important;\n  border: 0 !important;\n  border-radius: 11px !important;\n  background: transparent !important;\n  box-shadow: none !important;\n  color: inherit !important;\n  text-align: left !important;\n  cursor: pointer;\n}\n\n#oci-region-app .ociw-region-row:hover {\n  background: rgba(76,147,255,.075) !important;\n}\n\n#oci-region-app .ociw-code {\n  width: 36px;\n  height: 29px;\n  display: grid;\n  place-items: center;\n  border: 1px solid rgba(76,147,255,.18);\n  border-radius: 8px;\n  background: rgba(76,147,255,.09);\n  color: #8eb8ff;\n  font: 9px\/1 \"SFMono-Regular\", Consolas, monospace;\n}\n\n#oci-region-app .ociw-region-copy {\n  min-width: 0;\n}\n\n#oci-region-app .ociw-region-name {\n  overflow: hidden;\n  color: #dce7f7;\n  font-size: 11px;\n  line-height: 1.35;\n  font-weight: 650;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n}\n\n#oci-region-app .ociw-region-id {\n  margin-top: 3px;\n  overflow: hidden;\n  color: #586a82;\n  font: 8.5px\/1.4 \"SFMono-Regular\", Consolas, monospace;\n  white-space: nowrap;\n  text-overflow: ellipsis;\n}\n\n#oci-region-app .ociw-ip-dot {\n  width: 7px;\n  height: 7px;\n  border-radius: 50%;\n  background: #34445a;\n  box-shadow: 0 0 0 4px rgba(52,68,90,.12);\n}\n\n#oci-region-app .ociw-ip-dot.is-resolving {\n  background: #e3b561;\n  box-shadow: 0 0 10px rgba(227,181,97,.4);\n}\n\n#oci-region-app .ociw-ip-dot.is-ready {\n  background: var(--ociw-green);\n  box-shadow: 0 0 12px rgba(90,240,167,.58);\n}\n\n#oci-region-app .ociw-ip-dot.is-error {\n  background: #65748a;\n}\n\n#oci-region-app .ociw-empty {\n  padding: 28px 15px;\n  color: #738399;\n  text-align: center;\n  font-size: 11px;\n}\n\n\/* --------------------------------------------------------------------------\n   LEAFLET THEME COMPATIBILITY\n   These !important rules specifically prevent blog themes from resizing\n   map tiles\/markers with global img { max-width:100%; height:auto; } rules.\n   -------------------------------------------------------------------------- *\/\n\n#oci-region-app .leaflet-container {\n  position: relative !important;\n  overflow: hidden !important;\n  font-family: inherit !important;\n  background: #05090e !important;\n}\n\n#oci-region-app .leaflet-container img,\n#oci-region-app .leaflet-container .leaflet-tile,\n#oci-region-app .leaflet-container .leaflet-marker-icon,\n#oci-region-app .leaflet-container .leaflet-marker-shadow {\n  max-width: none !important;\n  max-height: none !important;\n  padding: 0 !important;\n  margin: 0 !important;\n  border: 0 !important;\n  border-radius: 0 !important;\n  box-shadow: none !important;\n}\n\n#oci-region-app .leaflet-container img.leaflet-tile {\n  width: 256px !important;\n  height: 256px !important;\n  object-fit: fill !important;\n}\n\n#oci-region-app .leaflet-control-zoom {\n  margin: 12px 0 0 12px !important;\n  border: 1px solid rgba(255,255,255,.09) !important;\n  border-radius: 10px !important;\n  overflow: hidden !important;\n  box-shadow: none !important;\n}\n\n#oci-region-app .leaflet-control-zoom a {\n  width: 30px !important;\n  height: 30px !important;\n  border: 0 !important;\n  border-bottom: 1px solid rgba(255,255,255,.07) !important;\n  border-radius: 0 !important;\n  background: rgba(8,14,22,.94) !important;\n  color: #c7d7ee !important;\n  font-size: 18px !important;\n  line-height: 30px !important;\n  text-decoration: none !important;\n}\n\n#oci-region-app .leaflet-control-attribution {\n  margin: 0 !important;\n  padding: 2px 5px !important;\n  background: rgba(5,9,14,.66) !important;\n  color: #536176 !important;\n  font-size: 8px !important;\n}\n\n#oci-region-app .leaflet-control-attribution a {\n  color: #73849c !important;\n  text-decoration: none !important;\n}\n\n#oci-region-app .ociw-marker-shell {\n  background: transparent !important;\n  border: 0 !important;\n}\n\n#oci-region-app .ociw-marker {\n  position: relative;\n  width: 15px;\n  height: 15px;\n  border: 3px solid #07101a;\n  border-radius: 50%;\n  background: #64dfff;\n  box-shadow:\n    0 0 0 1px rgba(100,223,255,.75),\n    0 0 16px rgba(91,229,255,.65);\n}\n\n#oci-region-app .ociw-marker::after {\n  content: \"\";\n  position: absolute;\n  inset: -7px;\n  border: 1px solid rgba(91,229,255,.42);\n  border-radius: 50%;\n  animation: ociw-pulse 2.2s ease-out infinite;\n}\n\n#oci-region-app .ociw-marker.is-resolving {\n  background: #e4b45e;\n  box-shadow:\n    0 0 0 1px rgba(228,180,94,.75),\n    0 0 14px rgba(228,180,94,.5);\n}\n\n#oci-region-app .ociw-marker.is-ready {\n  background: var(--ociw-green);\n  box-shadow:\n    0 0 0 1px rgba(90,240,167,.8),\n    0 0 17px rgba(90,240,167,.62);\n}\n\n#oci-region-app .ociw-marker.is-ready::after {\n  border-color: rgba(90,240,167,.45);\n}\n\n@keyframes ociw-pulse {\n  0%   { transform: scale(.55); opacity: .85; }\n  72%,\n  100% { transform: scale(1.45); opacity: 0; }\n}\n\n#oci-region-app .leaflet-tooltip.ociw-tooltip {\n  min-width: 275px !important;\n  max-width: 340px !important;\n  margin: 0 !important;\n  padding: 0 !important;\n  border: 1px solid rgba(91,229,255,.22) !important;\n  border-radius: 13px !important;\n  background: rgba(6,11,18,.965) !important;\n  color: #eef4ff !important;\n  box-shadow: 0 18px 55px rgba(0,0,0,.52) !important;\n  overflow: hidden !important;\n  white-space: normal !important;\n}\n\n#oci-region-app .leaflet-tooltip.ociw-tooltip::before {\n  display: none !important;\n}\n\n#oci-region-app .ociw-tip-head {\n  display: flex;\n  align-items: center;\n  justify-content: space-between;\n  gap: 14px;\n  padding: 12px 13px 10px;\n  border-bottom: 1px solid var(--ociw-line);\n}\n\n#oci-region-app .ociw-tip-city {\n  min-width: 0;\n  color: #f0f6ff;\n  font-size: 12px;\n  line-height: 1.35;\n  font-weight: 680;\n}\n\n#oci-region-app .ociw-tip-key {\n  flex: 0 0 auto;\n  color: #88b6ff;\n  font: 9px\/1 \"SFMono-Regular\", Consolas, monospace;\n}\n\n#oci-region-app .ociw-tip-body {\n  display: grid;\n  gap: 8px;\n  padding: 11px 13px 12px;\n}\n\n#oci-region-app .ociw-tip-line {\n  display: grid;\n  grid-template-columns: 72px minmax(0,1fr);\n  gap: 8px;\n  align-items: start;\n}\n\n#oci-region-app .ociw-tip-label {\n  color: #596a81;\n  font: 8px\/1.45 \"SFMono-Regular\", Consolas, monospace;\n  letter-spacing: .08em;\n}\n\n#oci-region-app .ociw-tip-value {\n  min-width: 0;\n  overflow-wrap: anywhere;\n  color: #b9c9dc;\n  font: 9px\/1.45 \"SFMono-Regular\", Consolas, monospace;\n}\n\n#oci-region-app .ociw-tip-value.is-ip {\n  color: #87f3bd;\n}\n\n#oci-region-app .ociw-tip-value.is-pending {\n  color: #d4ad66;\n}\n\n#oci-region-app .ociw-tip-value.is-muted {\n  color: #6b7b91;\n}\n\n#oci-region-app .ociw-footer {\n  display: flex;\n  justify-content: space-between;\n  gap: 12px;\n  margin-top: 13px;\n  color: #55657b;\n  font: 8.5px\/1.4 \"SFMono-Regular\", Consolas, monospace;\n  letter-spacing: .08em;\n}\n\n\/* Responsive to ARTICLE WIDTH, not viewport width. *\/\n@container ociRegionWidget (max-width: 900px) {\n  #oci-region-app .ociw-intro {\n    grid-template-columns: 1fr;\n  }\n\n  #oci-region-app .ociw-layout {\n    grid-template-columns: 1fr;\n  }\n\n  #oci-region-app .ociw-map-card {\n    height: 500px;\n  }\n\n  #oci-region-app .ociw-region-card {\n    height: 390px;\n  }\n\n  #oci-region-app .ociw-toolbar {\n    align-items: stretch;\n    flex-direction: column;\n  }\n\n  #oci-region-app .ociw-search-wrap {\n    flex-basis: auto;\n    width: 100%;\n  }\n\n  #oci-region-app .ociw-filters {\n    width: 100%;\n  }\n}\n\n@container ociRegionWidget (max-width: 560px) {\n  #oci-region-app .ociw-frame {\n    padding: 14px;\n    border-radius: 17px;\n  }\n\n  #oci-region-app .ociw-header {\n    align-items: flex-start;\n  }\n\n  #oci-region-app .ociw-live {\n    display: none;\n  }\n\n  #oci-region-app .ociw-intro > div:first-child {\n    padding: 22px 20px;\n  }\n\n  #oci-region-app .ociw-stats {\n    grid-template-columns: 1fr 1fr;\n  }\n\n  #oci-region-app .ociw-stat {\n    min-height: 87px;\n    padding: 14px;\n  }\n\n  #oci-region-app .ociw-stat > strong {\n    font-size: 25px;\n  }\n\n  #oci-region-app .ociw-map-card {\n    height: 430px;\n  }\n\n  #oci-region-app .ociw-map-note {\n    left: 10px;\n    right: 10px;\n    bottom: 10px;\n    max-width: none;\n  }\n\n  #oci-region-app .ociw-footer {\n    flex-direction: column;\n  }\n}\n<\/style>\n\n<script>\n(() => {\n  const ROOT = document.getElementById(\"oci-region-app\");\n  if (!ROOT || ROOT.dataset.ociInitialized === \"1\") return;\n  ROOT.dataset.ociInitialized = \"1\";\n\n  \/*\n   * OPTIONAL \u2014 YOUR OWN TEST SERVERS\n   * ------------------------------------------------------------------------\n   * If you have a VM\/test server in a region, put its public IP here.\n   * It takes priority over the live DNS-resolved OCI endpoint IP.\n   *\n   * Example:\n   *   \"ap-tokyo-1\": \"203.0.113.10\",\n   *   \"us-ashburn-1\": \"203.0.113.20\"\n   *\/\n  const CUSTOM_TEST_IPS = {\n    \/\/ \"ap-tokyo-1\": \"YOUR.IP.HERE\",\n    \/\/ \"us-ashburn-1\": \"YOUR.IP.HERE\"\n  };\n\nconst REGIONS = [\n      { name:\"Australia East (Sydney)\", id:\"ap-sydney-1\", city:\"Sydney\", country:\"Australia\", key:\"SYD\", realm:\"OC1\", ads:1, group:\"apac\", lat:-33.8688, lng:151.2093 },\n      { name:\"Australia Southeast (Melbourne)\", id:\"ap-melbourne-1\", city:\"Melbourne\", country:\"Australia\", key:\"MEL\", realm:\"OC1\", ads:1, group:\"apac\", lat:-37.8136, lng:144.9631 },\n\n      { name:\"Brazil East (Sao Paulo)\", id:\"sa-saopaulo-1\", city:\"Sao Paulo\", country:\"Brazil\", key:\"GRU\", realm:\"OC1\", ads:1, group:\"americas\", lat:-23.5505, lng:-46.6333 },\n      { name:\"Brazil Southeast (Vinhedo)\", id:\"sa-vinhedo-1\", city:\"Vinhedo\", country:\"Brazil\", key:\"VCP\", realm:\"OC1\", ads:1, group:\"americas\", lat:-23.0302, lng:-46.9833 },\n      { name:\"Canada Southeast (Montreal)\", id:\"ca-montreal-1\", city:\"Montreal\", country:\"Canada\", key:\"YUL\", realm:\"OC1\", ads:1, group:\"americas\", lat:45.5017, lng:-73.5673 },\n      { name:\"Canada Southeast (Toronto)\", id:\"ca-toronto-1\", city:\"Toronto\", country:\"Canada\", key:\"YYZ\", realm:\"OC1\", ads:1, group:\"americas\", lat:43.6532, lng:-79.3832 },\n      { name:\"Chile Central (Santiago)\", id:\"sa-santiago-1\", city:\"Santiago\", country:\"Chile\", key:\"SCL\", realm:\"OC1\", ads:1, group:\"americas\", lat:-33.4489, lng:-70.6693 },\n      { name:\"Chile West (Valparaiso)\", id:\"sa-valparaiso-1\", city:\"Valparaiso\", country:\"Chile\", key:\"VAP\", realm:\"OC1\", ads:1, group:\"americas\", lat:-33.0472, lng:-71.6127 },\n      { name:\"Colombia Central (Bogota)\", id:\"sa-bogota-1\", city:\"Bogota\", country:\"Colombia\", key:\"BOG\", realm:\"OC1\", ads:1, group:\"americas\", lat:4.7110, lng:-74.0721 },\n\n      { name:\"France Central (Paris)\", id:\"eu-paris-1\", city:\"Paris\", country:\"France\", key:\"CDG\", realm:\"OC1\", ads:1, group:\"europe\", lat:48.8566, lng:2.3522 },\n      { name:\"France South (Marseille)\", id:\"eu-marseille-1\", city:\"Marseille\", country:\"France\", key:\"MRS\", realm:\"OC1\", ads:1, group:\"europe\", lat:43.2965, lng:5.3698 },\n      { name:\"Germany Central (Frankfurt)\", id:\"eu-frankfurt-1\", city:\"Frankfurt\", country:\"Germany\", key:\"FRA\", realm:\"OC1\", ads:3, group:\"europe\", lat:50.1109, lng:8.6821 },\n\n      { name:\"India South (Hyderabad)\", id:\"ap-hyderabad-1\", city:\"Hyderabad\", country:\"India\", key:\"HYD\", realm:\"OC1\", ads:1, group:\"apac\", lat:17.3850, lng:78.4867 },\n      { name:\"India West (Mumbai)\", id:\"ap-mumbai-1\", city:\"Mumbai\", country:\"India\", key:\"BOM\", realm:\"OC1\", ads:1, group:\"apac\", lat:19.0760, lng:72.8777 },\n      { name:\"Indonesia North (Batam)\", id:\"ap-batam-1\", city:\"Batam\", country:\"Indonesia\", key:\"HSG\", realm:\"OC1\", ads:1, group:\"apac\", lat:1.0456, lng:104.0305 },\n\n      { name:\"Israel Central (Jerusalem)\", id:\"il-jerusalem-1\", city:\"Jerusalem\", country:\"Israel\", key:\"MTZ\", realm:\"OC1\", ads:1, group:\"mea\", lat:31.7683, lng:35.2137 },\n\n      { name:\"Italy Northwest (Milan)\", id:\"eu-milan-1\", city:\"Milan\", country:\"Italy\", key:\"LIN\", realm:\"OC1\", ads:1, group:\"europe\", lat:45.4642, lng:9.1900 },\n      { name:\"Italy North (Turin)\", id:\"eu-turin-1\", city:\"Turin\", country:\"Italy\", key:\"NRQ\", realm:\"OC1\", ads:1, group:\"europe\", lat:45.0703, lng:7.6869 },\n\n      { name:\"Japan Central (Osaka)\", id:\"ap-osaka-1\", city:\"Osaka\", country:\"Japan\", key:\"KIX\", realm:\"OC1\", ads:1, group:\"apac\", lat:34.6937, lng:135.5023 },\n      { name:\"Japan East (Tokyo)\", id:\"ap-tokyo-1\", city:\"Tokyo\", country:\"Japan\", key:\"NRT\", realm:\"OC1\", ads:1, group:\"apac\", lat:35.6762, lng:139.6503 },\n      { name:\"Malaysia West 2 (Kulai)\", id:\"ap-kulai-2\", city:\"Kulai\", country:\"Malaysia\", key:\"JBP\", realm:\"OC1\", ads:1, group:\"apac\", lat:1.6561, lng:103.6032 },\n\n      { name:\"Mexico Central (Queretaro)\", id:\"mx-queretaro-1\", city:\"Queretaro\", country:\"Mexico\", key:\"QRO\", realm:\"OC1\", ads:1, group:\"americas\", lat:20.5888, lng:-100.3899 },\n      { name:\"Mexico Northeast (Monterrey)\", id:\"mx-monterrey-1\", city:\"Monterrey\", country:\"Mexico\", key:\"MTY\", realm:\"OC1\", ads:1, group:\"americas\", lat:25.6866, lng:-100.3161 },\n\n      { name:\"Morocco West (Casablanca)\", id:\"af-casablanca-1\", city:\"Casablanca\", country:\"Morocco\", key:\"LEJ\", realm:\"OC1\", ads:1, group:\"mea\", lat:33.5731, lng:-7.5898 },\n      { name:\"Netherlands Northwest (Amsterdam)\", id:\"eu-amsterdam-1\", city:\"Amsterdam\", country:\"Netherlands\", key:\"AMS\", realm:\"OC1\", ads:1, group:\"europe\", lat:52.3676, lng:4.9041 },\n\n      { name:\"Saudi Arabia Central (Riyadh)\", id:\"me-riyadh-1\", city:\"Riyadh\", country:\"Saudi Arabia\", key:\"RUH\", realm:\"OC1\", ads:1, group:\"mea\", lat:24.7136, lng:46.6753 },\n      { name:\"Saudi Arabia West (Jeddah)\", id:\"me-jeddah-1\", city:\"Jeddah\", country:\"Saudi Arabia\", key:\"JED\", realm:\"OC1\", ads:1, group:\"mea\", lat:21.4858, lng:39.1925 },\n\n      { name:\"Serbia Central (Jovanovac)\", id:\"eu-jovanovac-1\", city:\"Jovanovac\", country:\"Serbia\", key:\"BEG\", realm:\"OC20\", ads:1, group:\"europe\", lat:44.018, lng:20.920 },\n\n      { name:\"Singapore (Singapore)\", id:\"ap-singapore-1\", city:\"Singapore\", country:\"Singapore\", key:\"SIN\", realm:\"OC1\", ads:1, group:\"apac\", lat:1.3521, lng:103.8198, displayLat:1.55, displayLng:103.68 },\n      { name:\"Singapore West (Singapore)\", id:\"ap-singapore-2\", city:\"Singapore\", country:\"Singapore\", key:\"XSP\", realm:\"OC1\", ads:1, group:\"apac\", lat:1.3521, lng:103.8198, displayLat:1.15, displayLng:103.98 },\n\n      { name:\"South Africa Central (Johannesburg)\", id:\"af-johannesburg-1\", city:\"Johannesburg\", country:\"South Africa\", key:\"JNB\", realm:\"OC1\", ads:1, group:\"mea\", lat:-26.2041, lng:28.0473 },\n      { name:\"South Korea Central (Seoul)\", id:\"ap-seoul-1\", city:\"Seoul\", country:\"South Korea\", key:\"ICN\", realm:\"OC1\", ads:1, group:\"apac\", lat:37.5665, lng:126.9780 },\n      { name:\"South Korea North (Chuncheon)\", id:\"ap-chuncheon-1\", city:\"Chuncheon\", country:\"South Korea\", key:\"YNY\", realm:\"OC1\", ads:1, group:\"apac\", lat:37.8813, lng:127.7298 },\n\n      { name:\"Spain Central (Madrid)\", id:\"eu-madrid-1\", city:\"Madrid\", country:\"Spain\", key:\"MAD\", realm:\"OC1\", ads:1, group:\"europe\", lat:40.4168, lng:-3.7038, displayLat:40.58, displayLng:-3.90 },\n      { name:\"Spain Central (Madrid 3)\", id:\"eu-madrid-3\", city:\"Madrid\", country:\"Spain\", key:\"ORF\", realm:\"OC1\", ads:1, group:\"europe\", lat:40.4168, lng:-3.7038, displayLat:40.22, displayLng:-3.48 },\n\n      { name:\"Sweden Central (Stockholm)\", id:\"eu-stockholm-1\", city:\"Stockholm\", country:\"Sweden\", key:\"ARN\", realm:\"OC1\", ads:1, group:\"europe\", lat:59.3293, lng:18.0686 },\n      { name:\"Switzerland North (Zurich)\", id:\"eu-zurich-1\", city:\"Zurich\", country:\"Switzerland\", key:\"ZRH\", realm:\"OC1\", ads:1, group:\"europe\", lat:47.3769, lng:8.5417 },\n\n      { name:\"UAE Central (Abu Dhabi)\", id:\"me-abudhabi-1\", city:\"Abu Dhabi\", country:\"UAE\", key:\"AUH\", realm:\"OC1\", ads:1, group:\"mea\", lat:24.4539, lng:54.3773 },\n      { name:\"UAE East (Dubai)\", id:\"me-dubai-1\", city:\"Dubai\", country:\"UAE\", key:\"DXB\", realm:\"OC1\", ads:1, group:\"mea\", lat:25.2048, lng:55.2708 },\n\n      { name:\"UK South (London)\", id:\"uk-london-1\", city:\"London\", country:\"United Kingdom\", key:\"LHR\", realm:\"OC1\", ads:3, group:\"europe\", lat:51.5072, lng:-0.1276 },\n      { name:\"UK West (Newport)\", id:\"uk-cardiff-1\", city:\"Newport\", country:\"United Kingdom\", key:\"CWL\", realm:\"OC1\", ads:1, group:\"europe\", lat:51.5842, lng:-2.9977 },\n\n      { name:\"US East (Ashburn)\", id:\"us-ashburn-1\", city:\"Ashburn\", country:\"United States\", key:\"IAD\", realm:\"OC1\", ads:3, group:\"americas\", lat:39.0438, lng:-77.4874 },\n      { name:\"US Midwest (Chicago)\", id:\"us-chicago-1\", city:\"Chicago\", country:\"United States\", key:\"ORD\", realm:\"OC1\", ads:3, group:\"americas\", lat:41.8781, lng:-87.6298 },\n      { name:\"US West (Phoenix)\", id:\"us-phoenix-1\", city:\"Phoenix\", country:\"United States\", key:\"PHX\", realm:\"OC1\", ads:3, group:\"americas\", lat:33.4484, lng:-112.0740 },\n      { name:\"US West (San Jose)\", id:\"us-sanjose-1\", city:\"San Jose\", country:\"United States\", key:\"SJC\", realm:\"OC1\", ads:1, group:\"americas\", lat:37.3382, lng:-121.8863 }\n    ]\n\n  const IP_CACHE_KEY = \"oci-region-widget-ip-cache-v2\";\n  const CACHE_TTL_MS = 6 * 60 * 60 * 1000;\n  const markers = new Map();\n\n  let activeFilter = \"all\";\n  let query = \"\";\n  let map = null;\n  let resolveDone = 0;\n  let resolveFailed = 0;\n\n  const $ = (selector) => ROOT.querySelector(selector);\n  const $$ = (selector) => [...ROOT.querySelectorAll(selector)];\n\n  function escapeHtml(value) {\n    return String(value ?? \"\")\n      .replaceAll(\"&\", \"&amp;\")\n      .replaceAll(\"<\", \"&lt;\")\n      .replaceAll(\">\", \"&gt;\")\n      .replaceAll('\"', \"&quot;\")\n      .replaceAll(\"'\", \"&#039;\");\n  }\n\n  function endpointFor(region) {\n    \/*\n      OC1 endpoints use oraclecloud.com.\n      Serbia Central is OC20; Oracle service endpoints use oraclecloud20.com.\n    *\/\n    const domain = region.realm === \"OC20\"\n      ? \"oraclecloud20.com\"\n      : \"oraclecloud.com\";\n\n    return `iaas.${region.id}.${domain}`;\n  }\n\n  function loadCache() {\n    try {\n      const raw = sessionStorage.getItem(IP_CACHE_KEY);\n      if (!raw) return {};\n      const parsed = JSON.parse(raw);\n      if (!parsed || Date.now() - parsed.time > CACHE_TTL_MS) return {};\n      return parsed.ips || {};\n    } catch {\n      return {};\n    }\n  }\n\n  const initialCache = loadCache();\n\n  REGIONS.forEach(region => {\n    region.testHost = endpointFor(region);\n    region.customIp = CUSTOM_TEST_IPS[region.id] || \"\";\n    region.testIp = region.customIp || initialCache[region.id] || \"\";\n    region.ipStatus = region.testIp ? \"ready\" : \"idle\";\n    region.ipSource = region.customIp ? \"custom\" : (region.testIp ? \"cache\" : \"\");\n    region._promise = null;\n  });\n\n  function saveCache() {\n    try {\n      const ips = {};\n      REGIONS.forEach(r => {\n        if (r.testIp && !r.customIp) ips[r.id] = r.testIp;\n      });\n      sessionStorage.setItem(\n        IP_CACHE_KEY,\n        JSON.stringify({ time: Date.now(), ips })\n      );\n    } catch {}\n  }\n\n  async function queryDnsGoogle(host) {\n    const response = await fetch(\n      `https:\/\/dns.google\/resolve?name=${encodeURIComponent(host)}&type=A`,\n      { method: \"GET\", mode: \"cors\", cache: \"no-store\" }\n    );\n    if (!response.ok) throw new Error(\"Google DNS HTTP \" + response.status);\n    const data = await response.json();\n    return (data.Answer || [])\n      .filter(x => x.type === 1 && \/^\\d{1,3}(?:\\.\\d{1,3}){3}$\/.test(x.data))\n      .map(x => x.data);\n  }\n\n  async function queryDnsCloudflare(host) {\n    const response = await fetch(\n      `https:\/\/cloudflare-dns.com\/dns-query?name=${encodeURIComponent(host)}&type=A`,\n      {\n        method: \"GET\",\n        mode: \"cors\",\n        cache: \"no-store\",\n        headers: { \"accept\": \"application\/dns-json\" }\n      }\n    );\n    if (!response.ok) throw new Error(\"Cloudflare DNS HTTP \" + response.status);\n    const data = await response.json();\n    return (data.Answer || [])\n      .filter(x => x.type === 1 && \/^\\d{1,3}(?:\\.\\d{1,3}){3}$\/.test(x.data))\n      .map(x => x.data);\n  }\n\n  async function resolveRegion(region, quiet = false) {\n    if (region.testIp) return region.testIp;\n    if (region._promise) return region._promise;\n\n    region.ipStatus = \"resolving\";\n    updateRegionVisual(region);\n\n    region._promise = (async () => {\n      let ips = [];\n\n      try {\n        ips = await queryDnsGoogle(region.testHost);\n      } catch (_) {\n        try {\n          ips = await queryDnsCloudflare(region.testHost);\n        } catch (_) {}\n      }\n\n      if (ips.length) {\n        region.testIp = ips[0];\n        region.ipStatus = \"ready\";\n        region.ipSource = \"dns\";\n        resolveDone++;\n        saveCache();\n      } else {\n        region.ipStatus = \"error\";\n        resolveFailed++;\n      }\n\n      updateRegionVisual(region);\n      updateResolveStats();\n\n      if (!quiet) {\n        const marker = markers.get(region.id);\n        if (marker && marker.getTooltip && marker.getTooltip()) {\n          marker.setTooltipContent(tooltipHtml(region));\n        }\n      }\n\n      return region.testIp || \"\";\n    })().finally(() => {\n      region._promise = null;\n    });\n\n    return region._promise;\n  }\n\n  function markerStateClass(region) {\n    if (region.ipStatus === \"ready\") return \"is-ready\";\n    if (region.ipStatus === \"resolving\") return \"is-resolving\";\n    return \"\";\n  }\n\n  function markerIcon(region) {\n    return L.divIcon({\n      className: \"ociw-marker-shell\",\n      html: `<div class=\"ociw-marker ${markerStateClass(region)}\"><\/div>`,\n      iconSize: [15, 15],\n      iconAnchor: [7, 7]\n    });\n  }\n\n  function ipDisplay(region) {\n    if (region.testIp) {\n      return `<span class=\"ociw-tip-value is-ip\">${escapeHtml(region.testIp)}<\/span>`;\n    }\n    if (region.ipStatus === \"resolving\") {\n      return `<span class=\"ociw-tip-value is-pending\">Resolving DNS\u2026<\/span>`;\n    }\n    if (region.ipStatus === \"error\") {\n      return `<span class=\"ociw-tip-value is-muted\">DNS lookup unavailable<\/span>`;\n    }\n    return `<span class=\"ociw-tip-value is-pending\">Waiting for DNS\u2026<\/span>`;\n  }\n\n  function tooltipHtml(region) {\n    const source =\n      region.ipSource === \"custom\" ? \"CUSTOM TEST IP\" :\n      region.ipSource === \"dns\" ? \"LIVE DNS\" :\n      region.ipSource === \"cache\" ? \"DNS CACHE\" : \"OCI ENDPOINT\";\n\n    return `\n      <div class=\"ociw-tip-head\">\n        <span class=\"ociw-tip-city\">${escapeHtml(region.city)}, ${escapeHtml(region.country)}<\/span>\n        <span class=\"ociw-tip-key\">${escapeHtml(region.key)}<\/span>\n      <\/div>\n      <div class=\"ociw-tip-body\">\n        <div class=\"ociw-tip-line\">\n          <span class=\"ociw-tip-label\">REGION<\/span>\n          <span class=\"ociw-tip-value\">${escapeHtml(region.id)}<\/span>\n        <\/div>\n        <div class=\"ociw-tip-line\">\n          <span class=\"ociw-tip-label\">REALM \/ AD<\/span>\n          <span class=\"ociw-tip-value\">${escapeHtml(region.realm)} \u00b7 ${region.ads} AD${region.ads > 1 ? \"s\" : \"\"}<\/span>\n        <\/div>\n        <div class=\"ociw-tip-line\">\n          <span class=\"ociw-tip-label\">TEST HOST<\/span>\n          <span class=\"ociw-tip-value\">${escapeHtml(region.testHost)}<\/span>\n        <\/div>\n        <div class=\"ociw-tip-line\">\n          <span class=\"ociw-tip-label\">TEST IP<\/span>\n          ${ipDisplay(region)}\n        <\/div>\n        <div class=\"ociw-tip-line\">\n          <span class=\"ociw-tip-label\">SOURCE<\/span>\n          <span class=\"ociw-tip-value\">${source}<\/span>\n        <\/div>\n      <\/div>\n    `;\n  }\n\n  function matches(region) {\n    if (activeFilter !== \"all\" && region.group !== activeFilter) return false;\n    if (!query) return true;\n\n    return [\n      region.name,\n      region.id,\n      region.city,\n      region.country,\n      region.key,\n      region.realm,\n      region.testHost,\n      region.testIp\n    ].join(\" \").toLowerCase().includes(query);\n  }\n\n  function updateResolveStats() {\n    const ready = REGIONS.filter(r => r.testIp).length;\n    $(\"#ociw-ip-count\").textContent = ready;\n\n    const unresolved = REGIONS.filter(r => !r.testIp && r.ipStatus !== \"error\").length;\n    const errors = REGIONS.filter(r => r.ipStatus === \"error\").length;\n\n    if (unresolved > 0) {\n      $(\"#ociw-resolve-state\").textContent = `${ready}\/45 resolved`;\n    } else if (errors > 0) {\n      $(\"#ociw-resolve-state\").textContent = `${ready} resolved \u00b7 ${errors} unavailable`;\n    } else {\n      $(\"#ociw-resolve-state\").textContent = \"45\/45 resolved\";\n    }\n  }\n\n  function updateRegionVisual(region) {\n    const marker = markers.get(region.id);\n\n    if (marker && window.L) {\n      marker.setIcon(markerIcon(region));\n      if (marker.getTooltip && marker.getTooltip()) {\n        marker.setTooltipContent(tooltipHtml(region));\n      }\n    }\n\n    const row = ROOT.querySelector(\n      `.ociw-region-row[data-region-id=\"${CSS.escape(region.id)}\"]`\n    );\n\n    if (row) {\n      const dot = row.querySelector(\".ociw-ip-dot\");\n      if (dot) {\n        dot.className =\n          \"ociw-ip-dot \" +\n          (region.ipStatus === \"ready\" ? \"is-ready\" :\n           region.ipStatus === \"resolving\" ? \"is-resolving\" :\n           region.ipStatus === \"error\" ? \"is-error\" : \"\");\n        dot.title =\n          region.testIp ? `Resolved IP: ${region.testIp}` :\n          region.ipStatus === \"resolving\" ? \"Resolving DNS\u2026\" :\n          \"No IP resolved yet\";\n      }\n    }\n  }\n\n  function renderListAndVisibility() {\n    const visible = REGIONS.filter(matches);\n\n    if (map) {\n      REGIONS.forEach(region => {\n        const marker = markers.get(region.id);\n        if (!marker) return;\n\n        if (matches(region)) {\n          if (!map.hasLayer(marker)) marker.addTo(map);\n        } else {\n          if (map.hasLayer(marker)) map.removeLayer(marker);\n        }\n      });\n    }\n\n    const list = $(\"#ociw-region-list\");\n    list.innerHTML = \"\";\n\n    if (!visible.length) {\n      list.innerHTML = `<div class=\"ociw-empty\">No OCI regions match your search.<\/div>`;\n    } else {\n      visible.forEach(region => {\n        const row = document.createElement(\"button\");\n        row.type = \"button\";\n        row.className = \"ociw-region-row\";\n        row.dataset.regionId = region.id;\n\n        row.innerHTML = `\n          <span class=\"ociw-code\">${escapeHtml(region.key)}<\/span>\n          <span class=\"ociw-region-copy\">\n            <span class=\"ociw-region-name\">${escapeHtml(region.name)}<\/span>\n            <span class=\"ociw-region-id\">${escapeHtml(region.id)} \u00b7 ${region.ads} AD${region.ads > 1 ? \"s\" : \"\"}<\/span>\n          <\/span>\n          <span class=\"ociw-ip-dot ${region.ipStatus === \"ready\" ? \"is-ready\" : region.ipStatus === \"resolving\" ? \"is-resolving\" : region.ipStatus === \"error\" ? \"is-error\" : \"\"}\"><\/span>\n        `;\n\n        row.addEventListener(\"mouseenter\", () => {\n          resolveRegion(region);\n          const marker = markers.get(region.id);\n          if (marker && map && map.hasLayer(marker)) marker.openTooltip();\n        });\n\n        row.addEventListener(\"mouseleave\", () => {\n          const marker = markers.get(region.id);\n          if (marker) marker.closeTooltip();\n        });\n\n        row.addEventListener(\"click\", async () => {\n          resolveRegion(region);\n          if (!map) return;\n          map.flyTo(\n            [region.displayLat ?? region.lat, region.displayLng ?? region.lng],\n            5,\n            { duration: .8 }\n          );\n          setTimeout(() => markers.get(region.id)?.openTooltip(), 520);\n        });\n\n        list.appendChild(row);\n      });\n    }\n\n    $(\"#ociw-list-meta\").textContent =\n      `${visible.length} region${visible.length === 1 ? \"\" : \"s\"} visible`;\n\n    updateResolveStats();\n  }\n\n  function ensureLeaflet() {\n    return new Promise((resolve, reject) => {\n      if (window.L && window.L.map) {\n        resolve();\n        return;\n      }\n\n      if (!document.getElementById(\"ociw-leaflet-css\")) {\n        const link = document.createElement(\"link\");\n        link.id = \"ociw-leaflet-css\";\n        link.rel = \"stylesheet\";\n        link.href = \"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.css\";\n        document.head.appendChild(link);\n      }\n\n      const existing = document.getElementById(\"ociw-leaflet-js\");\n      if (existing) {\n        existing.addEventListener(\"load\", resolve, { once: true });\n        existing.addEventListener(\"error\", reject, { once: true });\n        return;\n      }\n\n      const script = document.createElement(\"script\");\n      script.id = \"ociw-leaflet-js\";\n      script.src = \"https:\/\/unpkg.com\/leaflet@1.9.4\/dist\/leaflet.js\";\n      script.async = true;\n      script.onload = resolve;\n      script.onerror = reject;\n      document.head.appendChild(script);\n    });\n  }\n\n  function initMap() {\n    map = L.map(\"ociw-map\", {\n      zoomControl: true,\n      minZoom: 1.75,\n      maxZoom: 8,\n      worldCopyJump: true,\n      zoomSnap: .25,\n      attributionControl: true\n    }).setView([23, 8], 2.05);\n\n    L.tileLayer(\n      \"https:\/\/{s}.basemaps.cartocdn.com\/dark_nolabels\/{z}\/{x}\/{y}{r}.png\",\n      {\n        attribution: \"&copy; OpenStreetMap contributors &copy; CARTO\",\n        subdomains: \"abcd\",\n        maxZoom: 20,\n        noWrap: false\n      }\n    ).addTo(map);\n\n    const labels = L.tileLayer(\n      \"https:\/\/{s}.basemaps.cartocdn.com\/dark_only_labels\/{z}\/{x}\/{y}{r}.png\",\n      {\n        subdomains: \"abcd\",\n        maxZoom: 20,\n        pane: \"overlayPane\"\n      }\n    ).addTo(map);\n\n    labels.setOpacity(.47);\n\n    REGIONS.forEach(region => {\n      const marker = L.marker(\n        [region.displayLat ?? region.lat, region.displayLng ?? region.lng],\n        {\n          icon: markerIcon(region),\n          riseOnHover: true,\n          keyboard: true,\n          title: `${region.name} (${region.id})`\n        }\n      );\n\n      marker.bindTooltip(tooltipHtml(region), {\n        className: \"ociw-tooltip\",\n        direction: \"top\",\n        offset: [0, -12],\n        opacity: 1\n      });\n\n      marker.on(\"mouseover\", () => {\n        resolveRegion(region);\n      });\n\n      marker.on(\"focus\", () => {\n        resolveRegion(region);\n      });\n\n      marker.on(\"click\", () => {\n        resolveRegion(region);\n        map.flyTo(\n          [region.displayLat ?? region.lat, region.displayLng ?? region.lng],\n          Math.max(map.getZoom(), 4.75),\n          { duration: .75 }\n        );\n      });\n\n      marker.addTo(map);\n      markers.set(region.id, marker);\n    });\n\n    \/*\n      Blog themes often resize the article\/sidebar after the widget initializes.\n      ResizeObserver keeps Leaflet synchronized with the ACTUAL widget width.\n    *\/\n    const ro = new ResizeObserver(() => {\n      if (map) requestAnimationFrame(() => map.invalidateSize(false));\n    });\n    ro.observe($(\"#ociw-map\"));\n\n    window.addEventListener(\"load\", () => {\n      setTimeout(() => map?.invalidateSize(false), 100);\n      setTimeout(() => map?.invalidateSize(false), 500);\n    }, { once: true });\n\n    requestAnimationFrame(() => map.invalidateSize(false));\n    setTimeout(() => map.invalidateSize(false), 250);\n  }\n\n  async function resolveAllWithLimit(limit = 4) {\n    const queue = REGIONS.filter(r => !r.testIp);\n    let index = 0;\n\n    async function worker() {\n      while (index < queue.length) {\n        const region = queue[index++];\n        await resolveRegion(region, true);\n        await new Promise(r => setTimeout(r, 80));\n      }\n    }\n\n    $(\"#ociw-resolve-state\").textContent = \"Resolving regional IPs\u2026\";\n    await Promise.all(\n      Array.from({ length: Math.min(limit, queue.length) }, () => worker())\n    );\n    updateResolveStats();\n  }\n\n  $(\"#ociw-search\").addEventListener(\"input\", event => {\n    query = event.target.value.trim().toLowerCase();\n    renderListAndVisibility();\n  });\n\n  $$(\".ociw-filter\").forEach(button => {\n    button.addEventListener(\"click\", () => {\n      $$(\".ociw-filter\").forEach(x => x.classList.remove(\"is-active\"));\n      button.classList.add(\"is-active\");\n      activeFilter = button.dataset.filter;\n      renderListAndVisibility();\n    });\n  });\n\n  $(\"#ociw-region-count\").textContent = REGIONS.length;\n  $(\"#ociw-ad-count\").textContent =\n    REGIONS.reduce((sum, region) => sum + region.ads, 0);\n\n  renderListAndVisibility();\n\n  ensureLeaflet()\n    .then(() => {\n      initMap();\n      renderListAndVisibility();\n\n      \/*\n        Cached values display instantly.\n        Missing values are resolved in the background so the map gradually\n        turns green and hover tooltips already contain an IP when possible.\n      *\/\n      setTimeout(() => resolveAllWithLimit(4), 600);\n    })\n    .catch(error => {\n      console.error(\"OCI region widget: Leaflet failed to load\", error);\n      $(\"#ociw-resolve-state\").textContent = \"Map library failed to load\";\n      $(\"#ociw-map\").innerHTML = `\n        <div style=\"\n          height:100%;display:grid;place-items:center;padding:30px;\n          color:#8291a6;font:11px\/1.7 Consolas,monospace;text-align:center\">\n          The map library could not be loaded.<br>\n          Check whether your site's Content-Security-Policy allows unpkg.com\n          and basemaps.cartocdn.com.\n        <\/div>`;\n    });\n})();\n<\/script>\n","protected":false},"excerpt":{"rendered":"<p>Oracle Cloud Infrastructure Global Region Observatory INTERACTIVE MAP ONLINE OCI \/ COMMERCIAL CLOUD REGIONS Global infrastructure, one map. Hover over any region to see its OCI identifier, region key, Availability Domain count, regional test endpoint and resolved IP. REGIONS 45 AVAILABILITY DOMAINS 55 RESOLVED IPS 0 \/ 45 REALMS OC1 + OC20 \u2315 All Americas&#46;&#46;&#46;<\/p>\n","protected":false},"author":1,"featured_media":73,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[7],"tags":[],"class_list":["post-68","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tech"],"_links":{"self":[{"href":"https:\/\/haibara.us\/index.php?rest_route=\/wp\/v2\/posts\/68","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/haibara.us\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/haibara.us\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/haibara.us\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/haibara.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=68"}],"version-history":[{"count":4,"href":"https:\/\/haibara.us\/index.php?rest_route=\/wp\/v2\/posts\/68\/revisions"}],"predecessor-version":[{"id":72,"href":"https:\/\/haibara.us\/index.php?rest_route=\/wp\/v2\/posts\/68\/revisions\/72"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/haibara.us\/index.php?rest_route=\/wp\/v2\/media\/73"}],"wp:attachment":[{"href":"https:\/\/haibara.us\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=68"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/haibara.us\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=68"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/haibara.us\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=68"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}