{"id":775292,"date":"2025-12-08T17:40:45","date_gmt":"2025-12-08T09:40:45","guid":{"rendered":"https:\/\/www.tallship.com.sg\/?page_id=775292"},"modified":"2025-12-12T12:41:10","modified_gmt":"2025-12-12T04:41:10","slug":"asa-live-arrival-map-test","status":"publish","type":"page","link":"https:\/\/www.tallship.com.sg\/zh\/asa-live-arrival-map-test\/","title":{"rendered":"ASA Live Arrival Map (TEST)"},"content":{"rendered":"\t\t<div data-elementor-type=\"wp-page\" data-elementor-id=\"775292\" class=\"elementor elementor-775292\" data-elementor-post-type=\"page\">\n\t\t\t\t\t\t<section class=\"elementor-section elementor-top-section elementor-element elementor-element-a5b8e7f elementor-section-boxed elementor-section-height-default elementor-section-height-default\" data-id=\"a5b8e7f\" data-element_type=\"section\" data-e-type=\"section\">\n\t\t\t\t\t\t<div class=\"elementor-container elementor-column-gap-default\">\n\t\t\t\t\t<div class=\"elementor-column elementor-col-100 elementor-top-column elementor-element elementor-element-59b5ff8\" data-id=\"59b5ff8\" data-element_type=\"column\" data-e-type=\"column\">\n\t\t\t<div class=\"elementor-widget-wrap elementor-element-populated\">\n\t\t\t\t\t\t<div class=\"elementor-element elementor-element-e16f4bd elementor-widget elementor-widget-html\" data-id=\"e16f4bd\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<!DOCTYPE html>\r\n<html lang=\"en\">\r\n<head>\r\n  <meta charset=\"UTF-8\">\r\n  <title>ASA Live Tracker \u2013 Combined<\/title>\r\n  <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\r\n\r\n  <style>\r\n    \/* ---------- Base layout ---------- *\/\r\n    body {\r\n      margin: 0;\r\n      padding: 0;\r\n      font-family: system-ui, -apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif;\r\n      background: #f5f7fb;\r\n      color: #12335b;\r\n    }\r\n\r\n    .asa-wrapper {\r\n      max-width: 980px;\r\n      margin: 40px auto 60px;\r\n      padding: 0 16px;\r\n    }\r\n\r\n    .asa-title {\r\n      text-align: center;\r\n      font-size: 22px;\r\n      font-weight: 700;\r\n      margin-bottom: 8px;\r\n      letter-spacing: .06em;\r\n      text-transform: uppercase;\r\n      color: #123c7a;\r\n    }\r\n\r\n    .asa-subtitle {\r\n      text-align: center;\r\n      font-size: 12px;\r\n      color: #6c7f99;\r\n      margin-bottom: 24px;\r\n    }\r\n\r\n    \/* ---------- Status card ---------- *\/\r\n    .asa-status-card {\r\n      background: linear-gradient(135deg, #1369e6, #388bde, #1577ce);\r\n      border-radius: 12px;\r\n      color: #f5f8ff;\r\n      padding: 16px 20px 14px;\r\n      box-shadow: 0 18px 28px rgba(0, 60, 130, .18);\r\n      margin-bottom: 20px;\r\n    }\r\n\r\n    .asa-status-heading {\r\n      font-size: 11px;\r\n      text-transform: uppercase;\r\n      letter-spacing: .12em;\r\n      opacity: .8;\r\n      margin-bottom: 6px;\r\n    }\r\n\r\n    .asa-status-main {\r\n      font-size: 14px;\r\n      font-weight: 600;\r\n      margin-bottom: 6px;\r\n    }\r\n\r\n    .asa-last-updated {\r\n      font-size: 11px;\r\n      opacity: .9;\r\n    }\r\n\r\n    .asa-status-refresh {\r\n      font-size: 10px;\r\n      text-align: right;\r\n      opacity: .7;\r\n      margin-top: 6px;\r\n    }\r\n\r\n    \/* ---------- Table (desktop) ---------- *\/\r\n    .asa-table-wrapper {\r\n      background: #ffffff;\r\n      border-radius: 12px;\r\n      box-shadow: 0 6px 16px rgba(24, 71, 128, .06);\r\n      overflow: hidden;\r\n    }\r\n\r\n    table.asa-table {\r\n      width: 100%;\r\n      border-collapse: collapse;\r\n      font-size: 12px;\r\n    }\r\n\r\n    .asa-table thead {\r\n      background: #f6f8fc;\r\n    }\r\n\r\n    .asa-th {\r\n      padding: 9px 14px;\r\n      text-align: left;\r\n      border-bottom: 1px solid #e3e6f1;\r\n      font-size: 10px;\r\n      text-transform: uppercase;\r\n      letter-spacing: .1em;\r\n      color: #8a9ab3;\r\n      white-space: nowrap;\r\n    }\r\n\r\n    .asa-th-num { width: 60px; }\r\n    .asa-th-stop { width: 220px; }\r\n\r\n    .asa-td {\r\n      padding: 10px 14px;\r\n      border-bottom: 1px solid #edf0f7;\r\n      vertical-align: top;\r\n      background: #ffffff;\r\n    }\r\n\r\n    .asa-td-num {\r\n      color: #8a9ab3;\r\n      font-size: 11px;\r\n      white-space: nowrap;\r\n    }\r\n\r\n    .asa-td-stop {\r\n      font-weight: 500;\r\n      color: #1c355f;\r\n      font-size: 12px;\r\n    }\r\n\r\n    .asa-td-craft {\r\n      font-size: 12px;\r\n    }\r\n\r\n    tr:last-child .asa-td {\r\n      border-bottom: none;\r\n    }\r\n\r\n    \/* ---------- Craft lines inside combined column ---------- *\/\r\n    .asa-craft-block {\r\n      margin-bottom: 6px;\r\n    }\r\n\r\n    .asa-craft-header {\r\n      display: inline-flex;\r\n      align-items: center;\r\n      gap: 6px;\r\n      margin-bottom: 2px;\r\n    }\r\n\r\n    .asa-pill {\r\n      display: inline-flex;\r\n      align-items: center;\r\n      justify-content: center;\r\n      min-width: 26px;\r\n      padding: 2px 7px;\r\n      border-radius: 999px;\r\n      font-size: 10px;\r\n      font-weight: 700;\r\n      color: #ffffff;\r\n      text-transform: uppercase;\r\n      letter-spacing: .08em;\r\n    }\r\n\r\n    .asa-pill-na {\r\n      background: #1c78e4;\r\n      box-shadow: 0 0 0 1px rgba(16, 74, 150, .3);\r\n    }\r\n\r\n    .asa-pill-wa {\r\n      background: #f28b25;\r\n      box-shadow: 0 0 0 1px rgba(176, 89, 16, .35);\r\n    }\r\n\r\n    .asa-status-text {\r\n      font-size: 11px;\r\n      font-weight: 600;\r\n      color: #193967;\r\n    }\r\n\r\n    .asa-mins {\r\n      font-size: 11px;\r\n      color: #0d47a1;\r\n      margin-left: 32px; \/* indent under pill *\/\r\n    }\r\n\r\n    .asa-delay {\r\n      font-size: 10px;\r\n      color: #b6312f;\r\n      margin-left: 32px;\r\n    }\r\n\r\n    \/* \ud83d\udd34 ARRIVING SOON flash *\/\r\n    .asa-urgent {\r\n      color: #c62828;\r\n      font-weight: 800;\r\n      animation: asaFlash 1s infinite;\r\n    }\r\n\r\n    @keyframes asaFlash {\r\n      0% { opacity: 1; }\r\n      50% { opacity: 0.35; }\r\n      100% { opacity: 1; }\r\n    }\r\n\r\n    .asa-no-active {\r\n      font-size: 11px;\r\n      color: #9aa7bc;\r\n    }\r\n\r\n    \/* ---------- Footer line ---------- *\/\r\n    .asa-footer {\r\n      font-size: 10px;\r\n      text-align: center;\r\n      color: #a0acbf;\r\n      margin-top: 6px;\r\n      padding: 6px 0 0;\r\n    }\r\n\r\n    \/* ---------- Mobile cards ---------- *\/\r\n    .asa-mobile-list {\r\n      display: none;\r\n      margin-top: 16px;\r\n    }\r\n\r\n    .asa-mobile-card {\r\n      background: #ffffff;\r\n      border-radius: 12px;\r\n      box-shadow: 0 6px 16px rgba(24, 71, 128, .06);\r\n      padding: 10px 12px 10px;\r\n      margin-bottom: 10px;\r\n    }\r\n\r\n    .asa-mobile-header {\r\n      display: flex;\r\n      justify-content: space-between;\r\n      align-items: baseline;\r\n      margin-bottom: 6px;\r\n      gap: 8px;\r\n    }\r\n\r\n    .asa-mobile-stop {\r\n      font-size: 13px;\r\n      font-weight: 600;\r\n      color: #1c355f;\r\n    }\r\n\r\n    .asa-mobile-index {\r\n      font-size: 11px;\r\n      color: #8a9ab3;\r\n    }\r\n\r\n    .asa-mobile-crafts {\r\n      margin-top: 4px;\r\n    }\r\n\r\n    \/* ---------- Responsive ---------- *\/\r\n    @media (max-width: 768px) {\r\n      .asa-wrapper { margin: 24px auto 40px; }\r\n      .asa-title { font-size: 18px; }\r\n      .asa-table-wrapper { display: none; }\r\n      .asa-mobile-list { display: block; }\r\n      .asa-status-card { padding: 14px 14px 10px; }\r\n    }\r\n  <\/style>\r\n<\/head>\r\n\r\n<body>\r\n  <div class=\"asa-wrapper\">\r\n    <div class=\"asa-title\">ASA Live Tracker<\/div>\r\n    <div class=\"asa-subtitle\">\r\n      Resorts World Sentosa \u21c4 Ola Beach Club \u21c4 Sisters\u2019 Island \u21c4 Lazarus \u21c4 Kusu\r\n    <\/div>\r\n\r\n    <!-- Status card -->\r\n    <div class=\"asa-status-card\">\r\n      <div class=\"asa-status-heading\">Live Trip Status<\/div>\r\n      <div class=\"asa-status-main\" id=\"asa-status-main\">Loading route information\u2026<\/div>\r\n      <div class=\"asa-last-updated\" id=\"asa-last-updated\"><\/div>\r\n      <div class=\"asa-status-refresh\">Auto-refreshing every 10 seconds<\/div>\r\n    <\/div>\r\n\r\n    <!-- Desktop table -->\r\n    <div class=\"asa-table-wrapper\">\r\n      <table class=\"asa-table\">\r\n        <thead>\r\n          <tr>\r\n            <th class=\"asa-th asa-th-num\">#<\/th>\r\n            <th class=\"asa-th asa-th-stop\">Stop<\/th>\r\n            <th class=\"asa-th\">Craft status<\/th>\r\n          <\/tr>\r\n        <\/thead>\r\n        <tbody id=\"asa-table-body\">\r\n          <tr>\r\n            <td class=\"asa-td asa-td-num\">\u2013<\/td>\r\n            <td class=\"asa-td asa-td-stop\">Loading live data\u2026<\/td>\r\n            <td class=\"asa-td asa-td-craft\"><\/td>\r\n          <\/tr>\r\n        <\/tbody>\r\n      <\/table>\r\n      <div class=\"asa-footer\">\r\n        Live times update automatically \u00b7 Powered by ASA Marine Tracker\r\n      <\/div>\r\n    <\/div>\r\n\r\n    <!-- Mobile list -->\r\n    <div class=\"asa-mobile-list\" id=\"asa-mobile-list\"><\/div>\r\n  <\/div>\r\n\r\n  <script>\r\n    \/* ******************************************************\r\n     * CONFIG \u2013 your Apps Script web-app URL\r\n     * ****************************************************** *\/\r\n    const BASE_URL =\r\n      \"https:\/\/script.google.com\/macros\/s\/AKfycbxVFPo20pUX-6q2MhZgk_k4fu87e9ex_hVr5ofsgohJ3Wo_FTFV5aCfX6t6iO3ZFtt5\/exec\";\r\n    const NA_URL = BASE_URL + \"?boat=northern&json=1\";\r\n    const WA_URL = BASE_URL + \"?boat=wandering&json=1\";\r\n\r\n    \/\/ Sticky \"Arriving soon\" latch per craft+stop index\r\n    \/\/ Once true, stays true until that stop is marked Arrived.\r\n    const ARRIVING_SOON_LATCH = { NA: {}, WA: {} };\r\n\r\n    \/* ---------- Helpers ---------- *\/\r\n\r\n    function tripLabel(status) {\r\n      const s = (status || \"\").toUpperCase();\r\n      if (s === \"IN PROGRESS\") return \"Trip in progress\";\r\n      if (s === \"COMPLETED\")   return \"Trip completed\";\r\n      if (s === \"NOT STARTED\") return \"Not started\";\r\n      return status || \"\";\r\n    }\r\n\r\n    function isArrivedStatus(statusText) {\r\n      return (statusText || \"\").toUpperCase().includes(\"ARRIVED\");\r\n    }\r\n\r\n    \/\/ Try multiple possible ETA fields safely\r\n    function getEtaString(stopData) {\r\n      return (\r\n        stopData.etaText ||\r\n        stopData.ETA ||\r\n        stopData.eta ||\r\n        stopData.etaTime ||\r\n        stopData.etaStr ||\r\n        \"\"\r\n      ).toString().trim();\r\n    }\r\n\r\n    \/\/ Parse ETA like \"12:30\", \"12:30 PM\", \"12:30:26 PM\"\r\n    function etaToMsToday(etaStr) {\r\n      if (!etaStr) return null;\r\n\r\n      const now = new Date();\r\n\r\n      \/\/ If ISO date string exists, try it\r\n      const isoTry = Date.parse(etaStr);\r\n      if (!Number.isNaN(isoTry) && etaStr.includes(\"-\")) return isoTry;\r\n\r\n      const s = etaStr.replace(\/\\s+\/g, \" \").toUpperCase();\r\n      const m = s.match(\/^(\\d{1,2}):(\\d{2})(?::(\\d{2}))?(?:\\s*(AM|PM))?$\/);\r\n      if (!m) return null;\r\n\r\n      let hh = parseInt(m[1], 10);\r\n      const mm = parseInt(m[2], 10);\r\n      const ss = m[3] ? parseInt(m[3], 10) : 0;\r\n      const ap = m[4] || null;\r\n\r\n      if (ap) {\r\n        if (ap === \"AM\" && hh === 12) hh = 0;\r\n        if (ap === \"PM\" && hh !== 12) hh += 12;\r\n      }\r\n\r\n      const d = new Date(now);\r\n      d.setHours(hh, mm, ss, 0);\r\n      return d.getTime();\r\n    }\r\n\r\n    function computeCountdownFromETA(stopData) {\r\n      const etaStr = getEtaString(stopData);\r\n      const etaMs = etaToMsToday(etaStr);\r\n      if (!etaMs) return { text: \"\", urgent: false };\r\n\r\n      const diffMin = Math.ceil((etaMs - Date.now()) \/ 60000);\r\n      if (diffMin <= 0) return { text: \"Arriving soon\", urgent: true };\r\n      return { text: `Arriving in ${diffMin} minutes`, urgent: false };\r\n    }\r\n\r\n    function getMinutesNumber(stopData) {\r\n      const direct =\r\n        stopData.minutesToArrival ??\r\n        stopData.MinutesToArrival ??\r\n        stopData.minsToArrival ??\r\n        stopData.minsRemaining ??\r\n        null;\r\n\r\n      if (typeof direct === \"number\") return direct;\r\n\r\n      const s = (stopData.minsText || \"\").toString();\r\n      const m = s.match(\/(-?\\d+)\\s*minute\/i);\r\n      if (m) return parseInt(m[1], 10);\r\n\r\n      return null;\r\n    }\r\n\r\n    function buildCraftBlock(stopData, craftData, code, idx) {\r\n      if (!stopData || !craftData) return \"\";\r\n\r\n      let statusText = stopData.statusText || \"Pending \/ Not started\";\r\n      const arrived = isArrivedStatus(statusText);\r\n\r\n      \/\/ If arrived, force clean and clear latch\r\n      if (arrived) {\r\n        statusText = \"Arrived\";\r\n        delete ARRIVING_SOON_LATCH[code][idx];\r\n      }\r\n\r\n      \/\/ Minutes line (latched):\r\n      let minsText = \"\";\r\n      let urgent = false;\r\n\r\n      if (!arrived) {\r\n        const cd = computeCountdownFromETA(stopData);\r\n        const minsNum = getMinutesNumber(stopData);\r\n\r\n        const shouldTriggerSoon = (minsNum !== null && minsNum <= 0) || cd.urgent;\r\n        if (shouldTriggerSoon) ARRIVING_SOON_LATCH[code][idx] = true;\r\n\r\n        const latched = ARRIVING_SOON_LATCH[code][idx] === true;\r\n        if (latched) {\r\n          minsText = \"Arriving soon\";\r\n          urgent = true;\r\n        } else {\r\n          minsText = cd.text || (stopData.minsText || \"\");\r\n          urgent = cd.urgent;\r\n        }\r\n      }\r\n\r\n      \/\/ Delay line (hide if arrived)\r\n      const delayM = craftData.delayMinutes || 0;\r\n      const delayR = craftData.delayReason  || \"\";\r\n      let delayLine = \"\";\r\n\r\n      if (!arrived) {\r\n        if (delayM > 0) {\r\n          delayLine = \"Delay +\" + delayM + \" min\" + (delayR ? \" \u2013 \" + delayR : \"\");\r\n        } else if (delayR) {\r\n          delayLine = delayR;\r\n        }\r\n      }\r\n\r\n      const pillClass = code === \"NA\" ? \"asa-pill-na\" : \"asa-pill-wa\";\r\n\r\n      return `\r\n        <div class=\"asa-craft-block\">\r\n          <div class=\"asa-craft-header\">\r\n            <span class=\"asa-pill ${pillClass}\">${code}<\/span>\r\n            <span class=\"asa-status-text\">${statusText}<\/span>\r\n          <\/div>\r\n          ${minsText ? `<div class=\"asa-mins ${urgent ? \"asa-urgent\" : \"\"}\">${minsText}<\/div>` : \"\"}\r\n          ${delayLine ? `<div class=\"asa-delay\">${delayLine}<\/div>` : \"\"}\r\n        <\/div>\r\n      `;\r\n    }\r\n\r\n    function renderStatusBar(northern, wandering) {\r\n      const mainEl = document.getElementById(\"asa-status-main\");\r\n      const lastEl = document.getElementById(\"asa-last-updated\");\r\n\r\n      const naActive = northern && northern.tripStatus &&\r\n        northern.tripStatus.toUpperCase() !== \"NOT STARTED\";\r\n      const waActive = wandering && wandering.tripStatus &&\r\n        wandering.tripStatus.toUpperCase() !== \"NOT STARTED\";\r\n\r\n      const bits = [];\r\n      if (naActive) bits.push(\"Northern Albatross (NA) \u2013 \" + tripLabel(northern.tripStatus));\r\n      if (waActive) bits.push(\"Wandering Albatross (WA) \u2013 \" + tripLabel(wandering.tripStatus));\r\n\r\n      mainEl.textContent = bits.length ? bits.join(\" \u00b7 \") : \"No active trips at the moment.\";\r\n\r\n      const last =\r\n        (naActive && northern.lastUpdate)  ? northern.lastUpdate  :\r\n        (waActive && wandering.lastUpdate) ? wandering.lastUpdate :\r\n        (northern.lastUpdate || wandering.lastUpdate || \"\");\r\n\r\n      lastEl.textContent = last ? \"Last updated at \" + last : \"\";\r\n    }\r\n\r\n    function renderDesktopTable(northern, wandering) {\r\n      const tbody = document.getElementById(\"asa-table-body\");\r\n      tbody.innerHTML = \"\";\r\n\r\n      const naActive = northern && northern.tripStatus &&\r\n        northern.tripStatus.toUpperCase() !== \"NOT STARTED\";\r\n      const waActive = wandering && wandering.tripStatus &&\r\n        wandering.tripStatus.toUpperCase() !== \"NOT STARTED\";\r\n\r\n      if (!naActive && !waActive) return;\r\n\r\n      const source = (northern && northern.stops && northern.stops.length)\r\n        ? northern\r\n        : wandering;\r\n      const stops = (source && source.stops) ? source.stops : [];\r\n\r\n      stops.forEach((stop, idx) => {\r\n        const naStop = naActive ? (northern.stops[idx] || null) : null;\r\n        const waStop = waActive ? (wandering.stops[idx] || null) : null;\r\n\r\n        const craftHTML =\r\n          (naActive ? buildCraftBlock(naStop, northern, \"NA\", idx) : \"\") +\r\n          (waActive ? buildCraftBlock(waStop, wandering, \"WA\", idx) : \"\");\r\n\r\n        const tr = document.createElement(\"tr\");\r\n        tr.innerHTML = `\r\n          <td class=\"asa-td asa-td-num\">Stop ${stop.order}<\/td>\r\n          <td class=\"asa-td asa-td-stop\">${stop.name || \"\"}<\/td>\r\n          <td class=\"asa-td asa-td-craft\">\r\n            ${craftHTML}\r\n          <\/td>\r\n        `;\r\n        tbody.appendChild(tr);\r\n      });\r\n    }\r\n\r\n    function renderMobileList(northern, wandering) {\r\n      const container = document.getElementById(\"asa-mobile-list\");\r\n      container.innerHTML = \"\";\r\n\r\n      const naActive = northern && northern.tripStatus &&\r\n        northern.tripStatus.toUpperCase() !== \"NOT STARTED\";\r\n      const waActive = wandering && wandering.tripStatus &&\r\n        wandering.tripStatus.toUpperCase() !== \"NOT STARTED\";\r\n\r\n      if (!naActive && !waActive) return;\r\n\r\n      const source = (northern && northern.stops && northern.stops.length)\r\n        ? northern\r\n        : wandering;\r\n      const stops = (source && source.stops) ? source.stops : [];\r\n\r\n      stops.forEach((stop, idx) => {\r\n        const naStop = naActive ? (northern.stops[idx] || null) : null;\r\n        const waStop = waActive ? (wandering.stops[idx] || null) : null;\r\n\r\n        const craftHTML =\r\n          (naActive ? buildCraftBlock(naStop, northern, \"NA\", idx) : \"\") +\r\n          (waActive ? buildCraftBlock(waStop, wandering, \"WA\", idx) : \"\");\r\n\r\n        const card = document.createElement(\"div\");\r\n        card.className = \"asa-mobile-card\";\r\n        card.innerHTML = `\r\n          <div class=\"asa-mobile-header\">\r\n            <div class=\"asa-mobile-stop\">${stop.name || \"\"}<\/div>\r\n            <div class=\"asa-mobile-index\">Stop ${stop.order}<\/div>\r\n          <\/div>\r\n          <div class=\"asa-mobile-crafts\">\r\n            ${craftHTML || \"\"}\r\n          <\/div>\r\n        `;\r\n        container.appendChild(card);\r\n      });\r\n    }\r\n\r\n    function handleData(northern, wandering) {\r\n      renderStatusBar(northern, wandering);\r\n      renderDesktopTable(northern, wandering);\r\n      renderMobileList(northern, wandering);\r\n    }\r\n\r\n    function fetchJson(url) {\r\n      return fetch(url)\r\n        .then(r => r.json())\r\n        .catch(err => {\r\n          console.error(\"Error loading\", url, err);\r\n          return null;\r\n        });\r\n    }\r\n\r\n    function refreshData() {\r\n      Promise.all([fetchJson(NA_URL), fetchJson(WA_URL)])\r\n        .then(([na, wa]) => handleData(na || {}, wa || {}));\r\n    }\r\n\r\n    refreshData();\r\n    setInterval(refreshData, 10000);\r\n  <\/script>\r\n<\/body>\r\n<\/html>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t<div class=\"elementor-element elementor-element-b0c6c90 elementor-widget elementor-widget-html\" data-id=\"b0c6c90\" data-element_type=\"widget\" data-e-type=\"widget\" data-widget_type=\"html.default\">\n\t\t\t\t<div class=\"elementor-widget-container\">\n\t\t\t\t\t<style>\r\n\/* Desktop default *\/\r\n.asa-map-frame {\r\n  display: block;\r\n  width: 100%;\r\n  max-width: 680px;\r\n  height: 460px;\r\n  border: 0;\r\n  margin: 0 auto;\r\n}\r\n\r\n\/* Tablet *\/\r\n@media (max-width: 1024px) {\r\n  .asa-map-frame {\r\n    max-width: 100%;\r\n    height: 420px;\r\n  }\r\n}\r\n\r\n\/* Mobile *\/\r\n@media (max-width: 767px) {\r\n  .asa-map-frame {\r\n    max-width: 100%;\r\n    height: 320px;\r\n  }\r\n}\r\n<\/style>\r\n\r\n<div style=\"text-align:center;\">\r\n  <iframe\r\n    class=\"asa-map-frame\"\r\n    src=\"http:\/\/glympse.com\/!albatrossspeedboatadventures\"\r\n    allow=\"geolocation\"\r\n  ><\/iframe>\r\n<\/div>\r\n\t\t\t\t<\/div>\n\t\t\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/div>\n\t\t\t\t\t<\/div>\n\t\t<\/section>\n\t\t\t\t<\/div>\n\t\t","protected":false},"excerpt":{"rendered":"<p>ASA Live Tracker \u2013 Combined ASA Live Tracker Resorts World Sentosa \u21c4 Ola Beach Club \u21c4 Sisters\u2019 Island \u21c4 Lazarus \u21c4 Kusu Live Trip Status Loading route information\u2026 Auto-refreshing every 10 seconds # Stop Craft status \u2013 Loading live data\u2026 Live times update automatically \u00b7 Powered by ASA Marine Tracker<\/p>","protected":false},"author":59,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_acf_changed":false,"footnotes":""},"class_list":["post-775292","page","type-page","status-publish","hentry"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>ASA Live Arrival Map (TEST)<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.tallship.com.sg\/zh\/asa-live-arrival-map-test\/\" \/>\n<meta property=\"og:locale\" content=\"zh_CN\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"ASA Live Arrival Map (TEST)\" \/>\n<meta property=\"og:description\" content=\"ASA Live Tracker \u2013 Combined ASA Live Tracker Resorts World Sentosa \u21c4 Ola Beach Club \u21c4 Sisters\u2019 Island \u21c4 Lazarus \u21c4 Kusu Live Trip Status Loading route information\u2026 Auto-refreshing every 10 seconds # Stop Craft status \u2013 Loading live data\u2026 Live times update automatically \u00b7 Powered by ASA Marine Tracker\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.tallship.com.sg\/zh\/asa-live-arrival-map-test\/\" \/>\n<meta property=\"og:site_name\" content=\"Tallship\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/royalalbatross.sg\/\" \/>\n<meta property=\"article:modified_time\" content=\"2025-12-12T04:41:10+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.tallship.com.sg\/wp-content\/uploads\/2019\/05\/only-in-singapore-royal-albatross-ta2019.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"2000\" \/>\n\t<meta property=\"og:image:height\" content=\"900\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:site\" content=\"@royalalbatross_\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.tallship.com.sg\\\/asa-live-arrival-map-test\\\/\",\"url\":\"https:\\\/\\\/www.tallship.com.sg\\\/asa-live-arrival-map-test\\\/\",\"name\":\"ASA Live Arrival Map (TEST)\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.tallship.com.sg\\\/#website\"},\"datePublished\":\"2025-12-08T09:40:45+00:00\",\"dateModified\":\"2025-12-12T04:41:10+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.tallship.com.sg\\\/asa-live-arrival-map-test\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.tallship.com.sg\\\/asa-live-arrival-map-test\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.tallship.com.sg\\\/asa-live-arrival-map-test\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.tallship.com.sg\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"ASA Live Arrival Map (TEST)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.tallship.com.sg\\\/#website\",\"url\":\"https:\\\/\\\/www.tallship.com.sg\\\/\",\"name\":\"Tallship\",\"description\":\"Tallship\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.tallship.com.sg\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"ASA Live Arrival Map (TEST)","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.tallship.com.sg\/zh\/asa-live-arrival-map-test\/","og_locale":"zh_CN","og_type":"article","og_title":"ASA Live Arrival Map (TEST)","og_description":"ASA Live Tracker \u2013 Combined ASA Live Tracker Resorts World Sentosa \u21c4 Ola Beach Club \u21c4 Sisters\u2019 Island \u21c4 Lazarus \u21c4 Kusu Live Trip Status Loading route information\u2026 Auto-refreshing every 10 seconds # Stop Craft status \u2013 Loading live data\u2026 Live times update automatically \u00b7 Powered by ASA Marine Tracker","og_url":"https:\/\/www.tallship.com.sg\/zh\/asa-live-arrival-map-test\/","og_site_name":"Tallship","article_publisher":"https:\/\/www.facebook.com\/royalalbatross.sg\/","article_modified_time":"2025-12-12T04:41:10+00:00","og_image":[{"width":2000,"height":900,"url":"https:\/\/www.tallship.com.sg\/wp-content\/uploads\/2019\/05\/only-in-singapore-royal-albatross-ta2019.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_site":"@royalalbatross_","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.tallship.com.sg\/asa-live-arrival-map-test\/","url":"https:\/\/www.tallship.com.sg\/asa-live-arrival-map-test\/","name":"ASA Live Arrival Map (TEST)","isPartOf":{"@id":"https:\/\/www.tallship.com.sg\/#website"},"datePublished":"2025-12-08T09:40:45+00:00","dateModified":"2025-12-12T04:41:10+00:00","breadcrumb":{"@id":"https:\/\/www.tallship.com.sg\/asa-live-arrival-map-test\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.tallship.com.sg\/asa-live-arrival-map-test\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.tallship.com.sg\/asa-live-arrival-map-test\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.tallship.com.sg\/"},{"@type":"ListItem","position":2,"name":"ASA Live Arrival Map (TEST)"}]},{"@type":"WebSite","@id":"https:\/\/www.tallship.com.sg\/#website","url":"https:\/\/www.tallship.com.sg\/","name":"Tallship","description":"Tallship","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.tallship.com.sg\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"}]}},"_links":{"self":[{"href":"https:\/\/www.tallship.com.sg\/zh\/wp-json\/wp\/v2\/pages\/775292","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.tallship.com.sg\/zh\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.tallship.com.sg\/zh\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.tallship.com.sg\/zh\/wp-json\/wp\/v2\/users\/59"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tallship.com.sg\/zh\/wp-json\/wp\/v2\/comments?post=775292"}],"version-history":[{"count":3,"href":"https:\/\/www.tallship.com.sg\/zh\/wp-json\/wp\/v2\/pages\/775292\/revisions"}],"predecessor-version":[{"id":775471,"href":"https:\/\/www.tallship.com.sg\/zh\/wp-json\/wp\/v2\/pages\/775292\/revisions\/775471"}],"wp:attachment":[{"href":"https:\/\/www.tallship.com.sg\/zh\/wp-json\/wp\/v2\/media?parent=775292"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}