DEV Community

Cover image for AIRTIMES GLOBAL NETWORK
Gift Trust
Gift Trust

Posted on

AIRTIMES GLOBAL NETWORK

<!DOCTYPE html>




AIRTIMES — Global Network of Data & Free Services
:root { --bg: #020508; --sf: #060d14; --sf2: #0a1520; --ac: #00ffe0; --ac2: #0077ff; --ac3: #ff4d6d; --gd: #f5c518; --gd2: #ff9f00; --tx: #c8e8ff; --mt: #3a5570; } *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } html { scroll-behavior: smooth; } body { background: var(--bg); color: var(--tx); font-family: 'Space Mono', monospace; overflow-x: hidden; } .bg-layer { position: fixed; inset: 0; z-index: 0; pointer-events: none; background: radial-gradient(ellipse 80% 60% at 20% 10%, rgba(0,119,255,.07), transparent 70%), radial-gradient(ellipse 60% 50% at 80% 80%, rgba(0,255,224,.06), transparent 70%), radial-gradient(ellipse 40% 40% at 50% 50%, rgba(245,197,24,.03), transparent 70%); } .grid-overlay { position: fixed; inset: 0; z-index: 0; pointer-events: none; background-image: linear-gradient(rgba(0,255,224,.04) 1px, transparent 1px), linear-gradient(90deg, rgba(0,255,224,.04) 1px, transparent 1px); background-size: 48px 48px; animation: gridDrift 30s linear infinite; } @keyframes gridDrift { to { background-position: 48px 48px; } } .scanline { position: fixed; inset: 0; z-index: 1; pointer-events: none; background: repeating-linear-gradient(to bottom, transparent 0, transparent 3px, rgba(0,0,0,.06) 3px, rgba(0,0,0,.06) 4px); } .shell { position: relative; z-index: 2; } /* NAV */ nav { display: flex; align-items: center; justify-content: space-between; padding: 15px 38px; border-bottom: 1px solid rgba(0,255,224,.1); backdrop-filter: blur(14px); position: sticky; top: 0; z-index: 200; background: rgba(2,5,8,.9); } .logo { font-family: 'Bebas Neue'; font-size: 1.85rem; letter-spacing: .25em; color: var(--ac); text-shadow: 0 0 24px rgba(0,255,224,.5); cursor: pointer; position: relative; } .logo::after { content: '●'; font-size: .35em; color: var(--ac3); position: absolute; top: 4px; right: -14px; animation: blink 1.4s step-end infinite; } @keyframes blink { 50% { opacity: 0; } } .nl { display: flex; gap: 22px; list-style: none; } .nl a { color: var(--mt); text-decoration: none; font-size: .65rem; letter-spacing: .14em; text-transform: uppercase; transition: color .2s; cursor: pointer; } .nl a:hover { color: var(--ac); } .nl a.ga { color: var(--gd); } .nl a.ga:hover { color: var(--gd2); } .sp { display: flex; align-items: center; gap: 8px; font-size: .6rem; color: var(--ac); letter-spacing: .12em; } .pulse { width: 7px; height: 7px; border-radius: 50%; background: var(--ac); box-shadow: 0 0 8px var(--ac); animation: blink 1.4s step-end infinite; } /* TABS */ .tab-bar { display: flex; border-bottom: 1px solid rgba(0,255,224,.08); background: rgba(2,5,8,.75); position: sticky; top: 61px; z-index: 100; backdrop-filter: blur(10px); overflow-x: auto; } .tab { padding: 13px 22px; font-size: .62rem; letter-spacing: .15em; text-transform: uppercase; color: var(--mt); cursor: pointer; border-bottom: 2px solid transparent; transition: all .25s; white-space: nowrap; flex-shrink: 0; } .tab:hover { color: var(--tx); } .tab.active { color: var(--ac); border-bottom-color: var(--ac); } .tab.gt { color: rgba(245,197,24,.5); } .tab.gt:hover { color: var(--gd); } .tab.gt.active { color: var(--gd); border-bottom-color: var(--gd); } /* PAGES */ .page { display: none; animation: pi .3s ease; } .page.active { display: block; } @keyframes pi { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } } .sec { max-width: 1300px; margin: 0 auto; padding: 56px 40px; } .sl { font-size: .58rem; color: var(--ac); letter-spacing: .28em; text-transform: uppercase; margin-bottom: 8px; } .sl.gd { color: var(--gd); } .st { font-family: 'Bebas Neue'; font-size: 2.8rem; color: #fff; letter-spacing: .05em; margin-bottom: 28px; line-height: 1; } .sub { font-size: .76rem; color: var(--mt); line-height: 1.9; max-width: 640px; margin-bottom: 36px; } /* HERO */ .hero { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; align-items: center; padding: 76px 40px 56px; max-width: 1300px; margin: 0 auto; } .htag { font-size: .62rem; letter-spacing: .24em; text-transform: uppercase; color: var(--ac2); margin-bottom: 12px; display: flex; align-items: center; gap: 10px; } .htag::before { content: ''; width: 30px; height: 1px; background: var(--ac2); } h1 { font-family: 'Bebas Neue'; font-size: clamp(3.2rem,6.5vw,6rem); line-height: .92; letter-spacing: .05em; color: #fff; margin-bottom: 20px; } h1 .t { color: var(--ac); text-shadow: 0 0 25px rgba(0,255,224,.4); } h1 .r { color: var(--ac3); } h1 .g { color: var(--gd); } .hd { font-size: .78rem; line-height: 1.9; color: var(--mt); max-width: 420px; margin-bottom: 32px; } .ha { display: flex; gap: 10px; flex-wrap: wrap; } /* BUTTONS */ .btn { border: none; padding: 12px 24px; font-family: 'Space Mono'; font-size: .68rem; font-weight: 700; letter-spacing: .14em; text-transform: uppercase; cursor: pointer; transition: all .25s; } .bp { background: var(--ac); color: #000; clip-path: polygon(0 0,calc(100% - 10px) 0,100% 10px,100% 100%,0 100%); } .bp:hover { box-shadow: 0 0 28px rgba(0,255,224,.3); transform: translateY(-2px); } .bg { background: var(--gd); color: #000; clip-path: polygon(0 0,calc(100% - 10px) 0,100% 10px,100% 100%,0 100%); } .bg:hover { box-shadow: 0 0 28px rgba(245,197,24,.3); transform: translateY(-2px); } .bs { background: transparent; color: var(--tx); border: 1px solid var(--mt); } .bs:hover { border-color: var(--ac); color: var(--ac); } .bsm { padding: 8px 16px; font-size: .6rem; } /* GLOBE */ .gw { position: relative; display: flex; align-items: center; justify-content: center; height: 400px; } .globe { width: 290px; height: 290px; border-radius: 50%; background: radial-gradient(circle at 35% 35%, rgba(0,119,255,.25), transparent 60%), radial-gradient(circle at 50% 50%, #020d1a 40%, #010608 100%); border: 1px solid rgba(0,255,224,.15); box-shadow: 0 0 80px rgba(0,119,255,.2), inset 0 0 60px rgba(0,119,255,.1); animation: gp 6s ease-in-out infinite; } @keyframes gp { 50% { box-shadow: 0 0 120px rgba(0,119,255,.35), inset 0 0 80px rgba(0,119,255,.15); } } .orb { position: absolute; border-radius: 50%; border: 1px solid rgba(0,255,224,.12); } .o1 { width: 370px; height: 370px; animation: os 12s linear infinite; } .o2 { width: 450px; height: 450px; border-color: rgba(0,119,255,.08); animation: os 20s linear infinite reverse; } @keyframes os { to { transform: rotate(360deg); } } .on { position: absolute; width: 8px; height: 8px; border-radius: 50%; background: var(--ac); box-shadow: 0 0 12px var(--ac); top: -4px; left: 50%; transform: translateX(-50%); } .o2 .on { background: var(--ac2); box-shadow: 0 0 12px var(--ac2); } .sig { position: absolute; top: 50%; left: 50%; height: 1px; background: linear-gradient(90deg, rgba(0,255,224,.5), transparent); transform-origin: left; animation: sp 3s ease-in-out infinite; } @keyframes sp { 0% { opacity: 0; width: 0; } 40% { opacity: 1; } 100% { opacity: 0; width: 150px; } } .s1 { transform: rotate(35deg); } .s2 { transform: rotate(135deg); animation-delay: .8s; } .s3 { transform: rotate(220deg); animation-delay: 1.6s; } .s4 { transform: rotate(310deg); animation-delay: 2.4s; } .db { position: absolute; background: rgba(6,13,20,.92); border: 1px solid rgba(0,255,224,.2); padding: 7px 12px; font-size: .57rem; color: var(--ac); letter-spacing: .1em; backdrop-filter: blur(8px); animation: fu 4s ease-in-out infinite; } .db.b1 { top: 46px; left: 4px; } .db.b2 { bottom: 66px; right: -2px; animation-delay: 1.5s; color: var(--ac2); border-color: rgba(0,119,255,.3); } .db.b3 { top: 166px; right: -4px; animation-delay: .8s; color: var(--gd); border-color: rgba(245,197,24,.3); } @keyframes fu { 50% { transform: translateY(-8px); } } /* TICKER */ .tw { overflow: hidden; padding: 10px 0; border-top: 1px solid rgba(0,255,224,.07); border-bottom: 1px solid rgba(0,255,224,.07); background: rgba(0,255,224,.02); } .tt { display: flex; gap: 56px; white-space: nowrap; animation: ts 35s linear infinite; } @keyframes ts { to { transform: translateX(-50%); } } .ti { display: flex; align-items: center; gap: 10px; font-size: .62rem; letter-spacing: .14em; text-transform: uppercase; color: var(--mt); } .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--ac); } .dot.gd { background: var(--gd); } /* STATS ROW */ .sr { max-width: 1300px; margin: 50px auto; padding: 0 40px; display: grid; grid-template-columns: repeat(4,1fr); gap: 2px; } .sc { background: var(--sf); border: 1px solid rgba(0,255,224,.08); padding: 26px 22px; position: relative; overflow: hidden; transition: border-color .3s; } .sc:hover { border-color: rgba(0,255,224,.2); } .sc::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 2px; background: linear-gradient(90deg, transparent, var(--ac), transparent); opacity: 0; transition: opacity .3s; } .sc:hover::before { opacity: 1; } .sn { font-family: 'Bebas Neue'; font-size: 2.6rem; color: var(--ac); line-height: 1; margin-bottom: 4px; } .sn.b { color: var(--ac2); } .sn.r { color: var(--ac3); } .sn.gd { color: var(--gd); } .sl2 { font-size: .56rem; color: var(--mt); letter-spacing: .18em; text-transform: uppercase; } /* CARDS */ .cg { display: grid; grid-template-columns: repeat(3,1fr); gap: 2px; } .card { background: var(--sf); border: 1px solid rgba(0,255,224,.07); padding: 30px 24px; position: relative; overflow: hidden; cursor: pointer; transition: all .3s; } .card:hover { background: var(--sf2); border-color: rgba(0,255,224,.2); transform: translateY(-3px); } .card::after { content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 2px; background: linear-gradient(90deg, var(--ac2), var(--ac)); transform: scaleX(0); transform-origin: left; transition: transform .4s; } .card:hover::after { transform: scaleX(1); } .ci { font-size: 1.7rem; margin-bottom: 16px; } .cn { font-family: 'Syne'; font-size: .95rem; font-weight: 700; color: #fff; margin-bottom: 8px; } .cd { font-size: .68rem; line-height: 1.8; color: var(--mt); } .ctag { display: inline-block; margin-top: 14px; font-size: .54rem; letter-spacing: .17em; text-transform: uppercase; color: var(--ac); border: 1px solid rgba(0,255,224,.2); padding: 3px 9px; } .ctag.b { color: var(--ac2); border-color: rgba(0,119,255,.25); } .ctag.r { color: var(--ac3); border-color: rgba(255,77,109,.25); } .ctag.gd { color: var(--gd); border-color: rgba(245,197,24,.25); } /* FORMS */ .fp { background: var(--sf); border: 1px solid rgba(0,255,224,.1); padding: 32px; } .fp.gp { border-color: rgba(245,197,24,.2); } .fg { margin-bottom: 14px; } .fl { font-size: .56rem; color: var(--mt); letter-spacing: .2em; text-transform: uppercase; margin-bottom: 6px; display: block; } .fi { background: rgba(0,255,224,.03); border: 1px solid rgba(0,255,224,.15); color: var(--tx); padding: 10px 14px; font-family: 'Space Mono'; font-size: .7rem; outline: none; width: 100%; transition: border-color .2s; } .fi:focus { border-color: var(--ac); } .fi.gi { border-color: rgba(245,197,24,.2); } .fi.gi:focus { border-color: var(--gd); } .fi::placeholder { color: var(--mt); } select.fi option { background: #020508; } .rb { margin-top: 16px; background: rgba(0,255,224,.03); border: 1px solid rgba(0,255,224,.15); padding: 16px; font-size: .67rem; line-height: 2.2; display: none; } .rb.show { display: block; } .rb.gb { border-color: rgba(245,197,24,.2); background: rgba(245,197,24,.02); } .rk { color: var(--mt); } .rv { color: var(--ac); } .rv.gd { color: var(--gd); } .rv.g { color: #4ade80; } /* WALLET GRID */ .wg { display: grid; grid-template-columns: repeat(5,1fr); gap: 2px; margin-bottom: 28px; } .wc { background: var(--sf); border: 1px solid rgba(245,197,24,.12); padding: 22px 16px; text-align: center; cursor: pointer; transition: all .3s; position: relative; } .wc:hover { border-color: rgba(245,197,24,.4); background: rgba(245,197,24,.04); } .wc.sel { border-color: var(--gd); background: rgba(245,197,24,.06); } .wc.sel::before { content: '✓'; position: absolute; top: 7px; right: 9px; font-size: .58rem; color: var(--gd); } .wi { font-size: 1.9rem; margin-bottom: 7px; } .wco { font-family: 'Bebas Neue'; font-size: 1.15rem; color: var(--gd); letter-spacing: .1em; } .wna { font-size: .55rem; color: var(--mt); letter-spacing: .1em; margin-top: 2px; } .wad { font-size: .46rem; color: rgba(58,85,112,.55); margin-top: 7px; word-break: break-all; line-height: 1.4; } /* BUNDLE GRID */ .bg2 { display: grid; grid-template-columns: repeat(5,1fr); gap: 2px; margin-bottom: 22px; } .bc { background: var(--sf); border: 1px solid rgba(0,255,224,.08); padding: 20px 14px; text-align: center; cursor: pointer; transition: all .3s; } .bc:hover { border-color: rgba(0,255,224,.25); } .bc.sel { border-color: var(--ac); background: rgba(0,255,224,.04); } .bn { font-family: 'Bebas Neue'; font-size: 1rem; color: #fff; letter-spacing: .1em; } .bdata { font-size: 1.3rem; color: var(--ac); font-family: 'Bebas Neue'; line-height: 1.1; } .bprice { font-size: .6rem; color: var(--mt); margin-top: 4px; } .bbtc { font-size: .56rem; color: var(--gd); margin-top: 2px; } /* AIRBANK */ .vd { background: var(--sf); border: 1px solid rgba(0,255,224,.1); padding: 32px; margin-bottom: 2px; } .vn { font-family: 'Bebas Neue'; font-size: 3.5rem; color: var(--ac); line-height: 1; text-shadow: 0 0 40px rgba(0,255,224,.3); } .vu { font-size: .67rem; color: var(--mt); letter-spacing: .24em; text-transform: uppercase; margin-top: 4px; } .rg { display: grid; grid-template-columns: repeat(3,1fr); gap: 2px; margin-bottom: 2px; } .rc { background: var(--sf); border: 1px solid rgba(245,197,24,.1); padding: 26px; position: relative; } .rc::before { content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px; background: linear-gradient(90deg, transparent, var(--gd), transparent); } .rn { font-family: 'Bebas Neue'; font-size: 2.3rem; color: var(--gd); line-height: 1; margin-bottom: 4px; } .rl { font-size: .56rem; color: var(--mt); letter-spacing: .17em; text-transform: uppercase; } .rs { font-size: .6rem; color: rgba(245,197,24,.5); margin-top: 4px; } /* PROGRESS */ .pr { margin-bottom: 12px; } .pl { display: flex; justify-content: space-between; font-size: .58rem; color: var(--mt); letter-spacing: .1em; margin-bottom: 5px; } .pb { height: 4px; background: rgba(0,255,224,.08); border-radius: 2px; overflow: hidden; } .pf { height: 100%; border-radius: 2px; background: linear-gradient(90deg, var(--ac2), var(--ac)); animation: fb 2s ease forwards; transform-origin: left; } @keyframes fb { from { transform: scaleX(0); } to { transform: scaleX(1); } } .pf.gd { background: linear-gradient(90deg, var(--gd2), var(--gd)); } .pf.r { background: linear-gradient(90deg, var(--ac3), #ff9a6c); } /* TABLE */ .dt { width: 100%; border-collapse: collapse; font-size: .64rem; } .dt th { color: var(--mt); letter-spacing: .14em; text-transform: uppercase; font-size: .54rem; padding: 9px 13px; text-align: left; border-bottom: 1px solid rgba(0,255,224,.08); } .dt td { padding: 9px 13px; border-bottom: 1px solid rgba(255,255,255,.03); color: var(--tx); } .dt tr:hover td { background: rgba(0,255,224,.02); } .bdg { display: inline-block; padding: 2px 8px; font-size: .5rem; letter-spacing: .1em; text-transform: uppercase; border-radius: 2px; } .bg3 { background: rgba(0,255,224,.1); color: var(--ac); border: 1px solid rgba(0,255,224,.2); } .bgd { background: rgba(245,197,24,.1); color: var(--gd); border: 1px solid rgba(245,197,24,.2); } .br { background: rgba(255,77,109,.1); color: var(--ac3); border: 1px solid rgba(255,77,109,.2); } /* LOG FEED */ .lf { background: var(--sf); border: 1px solid rgba(0,255,224,.08); padding: 20px; min-height: 260px; } .le { display: flex; gap: 12px; padding: 8px 0; border-bottom: 1px solid rgba(255,255,255,.03); animation: fi .4s ease; } @keyframes fi { from { opacity: 0; transform: translateX(-8px); } to { opacity: 1; transform: none; } } .ld { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; margin-top: 5px; } .lg { background: var(--ac); box-shadow: 0 0 8px var(--ac); } .lb { background: var(--ac2); box-shadow: 0 0 8px var(--ac2); } .lr { background: var(--ac3); box-shadow: 0 0 8px var(--ac3); } .lgd { background: var(--gd); box-shadow: 0 0 8px var(--gd); } .lt { font-size: .62rem; line-height: 1.7; color: var(--mt); } .lt strong { color: var(--tx); font-weight: 400; } .ltm { font-size: .54rem; color: rgba(58,85,112,.5); display: block; margin-top: 1px; } /* SVG MAP */ .mc { width: 100%; height: 230px; position: relative; margin-top: 18px; } .ms { width: 100%; height: 100%; } /* HIGHLIGHT BOX */ .hb { background: rgba(245,197,24,.04); border: 1px solid rgba(245,197,24,.2); padding: 18px 22px; margin-bottom: 22px; } .hb p { font-size: .7rem; line-height: 1.9; color: var(--tx); } .hb strong { color: var(--gd); } /* CALC DISPLAY */ .cd { background: #000; border: 1px solid rgba(245,197,24,.2); padding: 18px; font-family: 'Bebas Neue'; font-size: 1.8rem; color: var(--gd); text-align: right; letter-spacing: .1em; min-height: 64px; margin-bottom: 14px; } .cd .cs { font-size: .76rem; color: rgba(245,197,24,.5); font-family: 'Space Mono'; } .copy-btn { background: rgba(245,197,24,.08); border: 1px solid rgba(245,197,24,.2); color: var(--gd); padding: 4px 12px; font-size: .56rem; cursor: pointer; font-family: 'Space Mono'; letter-spacing: .1em; transition: all .2s; } .copy-btn:hover { background: rgba(245,197,24,.18); } .div { border: none; border-top: 1px solid rgba(0,255,224,.06); margin: 36px 0; } .tc { display: grid; grid-template-columns: 1fr 1fr; gap: 2px; } .thc { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 2px; } /* FOOTER */ footer { border-top: 1px solid rgba(0,255,224,.06); padding: 30px 40px; display: flex; align-items: center; justify-content: space-between; max-width: 1300px; margin: 0 auto; } .fl2 { font-family: 'Bebas Neue'; font-size: 1.2rem; color: var(--mt); letter-spacing: .25em; } .fc { font-size: .54rem; color: rgba(58,85,112,.5); letter-spacing: .1em; } .fs { display: flex; align-items: center; gap: 8px; font-size: .58rem; color: var(--ac); letter-spacing: .15em; } @media (max-width: 900px) { .hero { grid-template-columns: 1fr; } .gw { height: 270px; } .globe { width: 220px; height: 220px; } .o1 { width: 280px; height: 280px; } .o2 { width: 350px; height: 350px; } .sr { grid-template-columns: repeat(2,1fr); } .cg { grid-template-columns: 1fr; } .wg { grid-template-columns: repeat(2,1fr); } .bg2 { grid-template-columns: repeat(2,1fr); } .rg { grid-template-columns: 1fr; } .tc { grid-template-columns: 1fr; } .thc { grid-template-columns: 1fr; } .nl { display: none; } nav { padding: 12px 18px; } .sec { padding: 40px 18px; } }

AIRTIMES


CONNECTING...

🌐 Home
⚡ Services
🔗 Connect
◯ Nodes
📡 Route
₿ AirPay
🏦 AirBank
👑 Owner Dashboard

  Global Data Mesh — v3.2.0
  <h1>FREE<br><span>DATA</span> &amp;<br><span>SERVICE</span><br><span>NETWORK</span>
Enter fullscreen mode Exit fullscreen mode

AIRTIMES delivers free data, connectivity, and digital services to every node on Earth. Users connect free. Owner earns automatically via AirPay crypto payments and AirBank data revenue — around the clock.

    GET FREE ACCESS
    ₿ BUY DATA BUNDLE
    🏦 AirBank







  ▲ 4,700 Gbps THROUGHPUT
  ◯ 142 ACTIVE NODES
  ₿ AUTO-EARNING ACTIVE





<span></span>AIRDATA FREE TIER ACTIVE
<span></span>AIRBANK — $0.0024 REVENUE LOGGED
<span></span>NAIROBI NODE ONLINE
<span></span>AIRPAY — BTC PAYMENT RECEIVED
<span></span>2.1M USERS CONNECTED
<span></span>AIRBANK VAULT — 842 TB STORED
<span></span>JAKARTA HUB — 340 Gbps
<span></span>AUTO-REVENUE TICKING EVERY SESSION
<span></span>AIRTIMES PROTOCOL v3.2 LIVE
<span></span>AIRPAY — ETH BUNDLE CONFIRMED
<span></span>AIRDATA FREE TIER ACTIVE
<span></span>AIRBANK — $0.0024 REVENUE LOGGED
<span></span>NAIROBI NODE ONLINE
<span></span>AIRPAY — BTC PAYMENT RECEIVED
<span></span>2.1M USERS CONNECTED
<span></span>AIRBANK VAULT — 842 TB STORED
<span></span>JAKARTA HUB — 340 Gbps
<span></span>AUTO-REVENUE TICKING EVERY SESSION
<span></span>AIRTIMES PROTOCOL v3.2 LIVE
<span></span>AIRPAY — ETH BUNDLE CONFIRMED




—Active Nodes Worldwide
—Daily Data Delivered (TB)
—Users Served Free
—Auto Revenue Earned (USD)



// Three Systems · One Network
HOW AIRTIMES WORKS


    🌐
    Free Global Network
    Users connect free worldwide via AirData, AirSMS, AirWeb, AirVault, AirAPI, AirRelay. Zero cost to users forever. Powered by surplus bandwidth redistribution across 142+ global nodes.
    FREE FOR ALL USERS


    ₿
    AirPay — Crypto Payments
    Users buy premium data bundles using Bitcoin, Ethereum, USDT, BNB, or Litecoin. Every payment routes directly to the owner's crypto wallet instantly. No middleman, no processor fees.
    BTC · ETH · USDT · BNB · LTC


    🏦
    AirBank — Auto Revenue Engine
    Every byte transmitted earns the owner automatically. Trillions of AirUnits stored in the vault, converted to direct money on every user session. Earn while you sleep.
    EARN AUTOMATICALLY







    📋 Live Network Events


    💰 Revenue Snapshot
    Loading revenue data...
    VIEW FULL OWNER DASHBOARD →









// All Free + Paid Services
WHAT AIRTIMES PROVIDES

  📡AirData — Free Mobile DataZero-cost mobile internet routing through the AIRTIMES mesh. Any device, any carrier, any country. Bandwidth pooled from surplus commercial nodes globally.FREE · UNLIMITED
  💬AirSMS — Global MessagingEnd-to-end encrypted SMS and voice relay across all 193 countries. Delivered free via spare spectrum on partner networks. Auto-revenue for owner per SMS.FREE · E2E ENCRYPTED
  🌐AirWeb — Open BrowserCompressed web proxy serving the full open internet at zero data cost. Optimized for low-bandwidth environments and offline caching. Up to 70% compression ratio.FREE · COMPRESSED
  🔗AirAPI — Open Data GatewayFree access to global datasets: weather, finance, health, transport. 50,000 requests/day per node. Developer-grade REST and WebSocket access.FREE · 50K RPD
  🛰AirRelay — Satellite FallbackWhen ground infrastructure fails, AIRTIMES auto-routes through low-earth-orbit relay partners to maintain continuous free connectivity globally.RESILIENT · AUTO
  💾AirVault — Distributed Storage5 GB of free distributed cloud storage per user. Sharded across 8+ geo-regions for redundancy. Served at zero cost from network surplus capacity.FREE · 5 GB
  ₿AirPay — Crypto Payment GatewayUsers buy premium data bundles with Bitcoin, Ethereum, USDT, BNB, or Litecoin. Payments go directly to the owner's wallet. No middleman. Instant settlement.BTC · ETH · USDT · BNB · LTC
  🏦AirBank — Auto Revenue EngineEvery user session generates automatic revenue for the owner. Trillions of AirUnits stored and converted to direct money. Revenue from data, SMS, API, storage.AUTO REVENUE
  🗺AirRoute — Smart Mesh RoutingDijkstra mesh routing with Haversine geo-scoring. Auto-failover. Multi-hop path optimization. Load rebalancing every 30 seconds across all nodes.AI ROUTING








// Free Access
JOIN THE NETWORK
<p>Register your phone or email to get a free AIRTIMES token. Instantly connected to 142+ nodes worldwide. No credit card. No contracts. Forever free.</p>


    Phone or Email

    Identifier Type
      EmailPhone
    ACTIVATE FREE ACCESS →
    <span>Fill in your details and click activate.</span>


    What you get FREE:

      ✦ AirData — Unlimited free mobile internet<br>
      ✦ AirSMS — Global encrypted messaging<br>
      ✦ AirWeb — Compressed web proxy<br>
      ✦ AirAPI — 50,000 free API calls/day<br>
      ✦ AirVault — 5 GB free cloud storage<br>
      ✦ AirRelay — Satellite connectivity fallback<br>
      ✦ Assigned to nearest global mesh node<br>
      ✦ 10 GB daily data quota<br>

    <hr>
    Want more data? <span>Buy a premium bundle with crypto via AirPay →</span>


<hr>
// Free API Test
AIRAPI GATEWAY


    City (Free Weather)

    GET FREE WEATHER →
    Exchange Rate



        GET RATE


    <span>Results appear here — all free, no API key needed.</span>


    🌐 AirAPI Specs

      ● <span>50,000</span> free calls/day per node<br>
      ● Weather data for all cities worldwide<br>
      ● Live exchange rates (150+ currencies)<br>
      ● Health, transport, finance datasets<br>
      ● REST + WebSocket endpoints<br>
      ● No API key needed for free tier<br>
      ● Each call auto-earns revenue for owner<br>










// Mesh Routing Engine
TEST YOUR ROUTE
<p>Enter your token and destination to compute the optimal mesh path through AIRTIMES global nodes using Haversine geo-scoring and Dijkstra path finding.</p>


    Your Token (from registration)

    Destination

    Service

        AirDataAirSMSAirWeb
        AirAPIAirVaultAirRelay

    COMPUTE ROUTE →


    Run a route test to see your full mesh path, latency estimate, hop count, and protocol details.









// Global Infrastructure
LIVE NODE MAP

  <svg>
    <line x1="0" y1="80" x2="900" y2="80" stroke="" stroke-width="1"></line>
    <line x1="0" y1="160" x2="900" y2="160" stroke="" stroke-width="1"></line>
    <line x1="225" y1="0" x2="225" y2="240" stroke="" stroke-width="1"></line>
    <line x1="450" y1="0" x2="450" y2="240" stroke="" stroke-width="1"></line>
    <line x1="675" y1="0" x2="675" y2="240" stroke="" stroke-width="1"></line>
    <g stroke="" stroke-width="1" fill="none">
      <line x1="80" y1="90" x2="200" y2="70"></line><line x1="200" y1="70" x2="340" y2="100"></line>
      <line x1="340" y1="100" x2="480" y2="80"></line><line x1="480" y1="80" x2="600" y2="110"></line>
      <line x1="600" y1="110" x2="740" y2="90"></line><line x1="740" y1="90" x2="840" y2="100"></line>
      <line x1="200" y1="70" x2="280" y2="150"></line><line x1="480" y1="80" x2="520" y2="170"></line>
      <line x1="600" y1="110" x2="580" y2="180"></line><line x1="80" y1="90" x2="120" y2="180"></line>
    </g>
    <circle r="3" fill=""><path d="M80,90 L200,70 L340,100 L480,80 L600,110 L740,90 L840,100"></path></circle>
    <circle r="2.5" fill=""><path d="M840,100 L740,90 L600,110 L480,80 L340,100 L200,70 L80,90"></path></circle>
    <g>
      <circle cx="80" cy="90" r="9" fill="" stroke="" stroke-width="1.5"></circle><circle cx="80" cy="90" r="3.5" fill="#00ffe0"></circle>NYC
      <circle cx="200" cy="70" r="10" fill="" stroke="" stroke-width="1.5"></circle><circle cx="200" cy="70" r="4" fill="#00ffe0"></circle>LDN
      <circle cx="340" cy="100" r="7" fill="" stroke="" stroke-width="1.5"></circle><circle cx="340" cy="100" r="3" fill="#0077ff"></circle>NBI
      <circle cx="480" cy="80" r="9" fill="" stroke="" stroke-width="1.5"></circle><circle cx="480" cy="80" r="4" fill="#f5c518"></circle>DXB
      <circle cx="600" cy="110" r="8" fill="" stroke="" stroke-width="1.5"></circle><circle cx="600" cy="110" r="3.5" fill="#ff4d6d"></circle>JKT
      <circle cx="740" cy="90" r="9" fill="" stroke="" stroke-width="1.5"></circle><circle cx="740" cy="90" r="4" fill="#00ffe0"></circle>TYO
      <circle cx="840" cy="100" r="7" fill="" stroke="" stroke-width="1"></circle><circle cx="840" cy="100" r="3" fill="#00ffe0"></circle>SYD
      <circle cx="120" cy="180" r="5" fill="" stroke="" stroke-width="1"></circle><circle cx="120" cy="180" r="2" fill="#0077ff"></circle>GRU
      <circle cx="520" cy="170" r="5" fill="" stroke="" stroke-width="1"></circle><circle cx="520" cy="170" r="2" fill="#0077ff"></circle>BOM
      <circle cx="580" cy="180" r="5" fill="" stroke="" stroke-width="1"></circle><circle cx="580" cy="180" r="2" fill="#ff4d6d"></circle>SIN
      <circle cx="660" cy="50" r="6" fill="" stroke="" stroke-width="1"></circle><circle cx="660" cy="50" r="2.5" fill="#0077ff"></circle>SHA
      <circle cx="155" cy="105" r="5" fill="" stroke="" stroke-width="1"></circle><circle cx="155" cy="105" r="2" fill="#f5c518"></circle>LOS
    </g>
  </svg>

<table id="nodes-table">
  <thead><tr>
Enter fullscreen mode Exit fullscreen mode
Node ID
City
Country
Operator
Capacity (Gbps)
Load
Status

Loading nodes...
// Bitcoin &amp; Crypto Payment Gateway
₿ AIRPAY

  <p>AirPay lets users buy premium data bundles using <strong>Bitcoin, Ethereum, USDT, BNB, or Litecoin</strong>. Every payment goes <strong>directly to the AIRTIMES owner's crypto wallet</strong> — instantly, no middleman, zero processor fees. Select a bundle, choose your crypto, and send payment to the displayed address.</p>


// Owner Wallet Addresses — All Payments Are Sent Directly Here


<hr>
// Select Your Data Bundle
Choose how much premium data you want to purchase:




    ⚡ Generate Payment Address
    Your User ID (optional)

    Pay With

        ₿ Bitcoin (BTC)
        Ξ Ethereum (ETH)
        ₮ Tether USDT (TRC-20)
        ⬡ BNB Coin
        Ł Litecoin (LTC)

    GENERATE PAYMENT ADDRESS →
    <span>Select a bundle above, then click to generate your payment address.</span>


    📋 How AirPay Works

      <span>Step 1.</span> Select a data bundle above<br>
      <span>Step 2.</span> Choose Bitcoin, ETH, USDT, BNB, or LTC<br>
      <span>Step 3.</span> Click "Generate Payment Address"<br>
      <span>Step 4.</span> Send exact crypto amount shown<br>
      <span>Step 5.</span> Bundle activates in 10–60 minutes<br>
      <span>Step 6.</span> Revenue automatically in owner wallet<br>

    <hr>
    All payments go directly to owner's crypto wallets. No processor. No fees. Direct blockchain settlement.



<hr>
// Confirm Your Payment


    Payment ID

    Transaction Hash (TX Hash from blockchain)

    CONFIRM PAYMENT →
    <span>Enter Payment ID + TX hash to confirm your purchase.</span>


    After sending crypto, paste your <span>Payment ID</span> and the <span>transaction hash</span> from your wallet or blockchain explorer. Data bundle activates immediately upon confirmation.









// Data Storage &amp; Automatic Revenue Engine
🏦 AIRBANK

  <p>AirBank is the <strong>financial backbone of AIRTIMES</strong>. Every byte of data transmitted through the network is stored in the AirBank Vault measured in <strong>Trillions of AirUnits</strong>. When users browse, message, stream, or use any AIRTIMES service — the owner <strong>earns money automatically</strong>, around the clock. Data is the currency. Usage is the revenue. Extract data, convert to direct money.</p>





    Vault Storage
    —
    Total AirUnits Stored


    Data Transmitted
    —
    GB Delivered to Users


    Total Revenue Earned
    —
    USD Earned Automatically






    Per GB Transmitted
    $0.002
    Every 1 GB routed = $0.002 earned by owner


    Per Active User / Day
    $0.001
    Every daily user session earns automatically


    Per API Call
    $0.00005
    Every AirAPI request generates revenue



<hr>
// Data → Money Calculator
Enter any amount of stored/transmitted data to see the revenue it generates for the owner:


    $ 0.00Enter amount below to calculate




          GBTBPB



    <span>Enter data amount above to calculate automatic revenue.</span>


    📈 Revenue Sources Breakdown
    <span>Data Transmission</span><span id="pct1">42%</span>
    <span>Active Users (Daily)</span><span id="pct2">24%</span>
    <span>AirPay Bundles</span><span id="pct3">18%</span>
    <span>API Calls</span><span id="pct4">9%</span>
    <span>Storage Fees</span><span id="pct5">5%</span>
    <span>SMS Revenue</span><span id="pct6">2%</span>









// Private Owner Control Panel
👑 OWNER DASHBOARD

  <p>This is your <strong>private revenue command center</strong>. See every dollar earned, every AirPay payment received, every data unit transmitted. <strong>Set your Bitcoin and crypto wallet addresses below</strong> — all AirPay payments route directly to these wallets instantly. You own the network. You own the revenue.</p>



// ₿ Your Crypto Wallet Addresses
Enter your real wallet addresses here. Users see these when paying via AirPay. All payments land directly in your wallets.


    ₿ Bitcoin (BTC) Wallet Address

    Ξ Ethereum (ETH) Wallet Address

    ₮ USDT Wallet (TRC-20 / Tron Network)

    ⬡ BNB Wallet Address

    Ł Litecoin (LTC) Wallet Address


      SAVE WALLET ADDRESSES →



    <span>Enter your real wallet addresses and click Save. These will be shown to users on the AirPay page. For production, set as environment variables on your backend server.</span>




// Revenue Summary

  Total Earned (USD)$—— BTC
  Projected Monthly$—Based on current daily rate
  Revenue Events Logged—Auto-logged transactions




    Revenue by Source
    Loading...


    Daily Revenue (Last 7 Days)
    Loading...





  AirPay Payment History
  <table>
    <thead><tr>
Enter fullscreen mode Exit fullscreen mode
Payment ID
Bundle
Coin
Amount
Status
Date

No payments yet. Share your AirPay page with users to start receiving crypto payments!
<hr>
// Network Control


    Registered Users
    —
    Total on network


    Active Nodes
    —
    Online globally


    Data Routed Today
    —
    GB transmitted
Enter fullscreen mode Exit fullscreen mode

AIRTIMES
© 2025 AIRTIMES GLOBAL NETWORK · AirPay · AirBank · All Services Free · All Rights Universal
ALL SYSTEMS OPERATIONAL

<!-- /shell --> /* ===== CONFIG ===== */ const API = (window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') ? 'http://localhost:3001' : ''; /* ===== WALLET STATE (saved in localStorage) ===== */ let WALLETS = { BTC: localStorage.getItem('w_BTC') || '', ETH: localStorage.getItem('w_ETH') || '', USDT: localStorage.getItem('w_USDT') || '', BNB: localStorage.getItem('w_BNB') || '', LTC: localStorage.getItem('w_LTC') || '' }; const COIN_ICONS = { BTC:'&#8383;', ETH:'&#926;', USDT:'&#8366;', BNB:'&#11041;', LTC:'&#321;' }; const COIN_NAMES = { BTC:'Bitcoin', ETH:'Ethereum', USDT:'Tether TRC-20', BNB:'BNB Coin', LTC:'Litecoin' }; const COIN_RATES = { BTC:0.0000155, ETH:0.000290, USDT:1.0, BNB:0.00310, LTC:0.0120 }; const BUNDLES = [ { id:'starter', name:'Starter', gb:5, usd:0.50, btc:'0.000010' }, { id:'basic', name:'Basic', gb:20, usd:1.99, btc:'0.000038' }, { id:'standard', name:'Standard', gb:100, usd:7.99, btc:'0.000150' }, { id:'pro', name:'Pro', gb:500, usd:29.99, btc:'0.000600' }, { id:'unlimited', name:'Unlimited', gb:9999, usd:74.99, btc:'0.001500' } ]; let selBundle = null; /* ===== PAGE SWITCHER ===== */ function P(id) { document.querySelectorAll('.page').forEach(p => p.classList.remove('active')); document.querySelectorAll('.tab').forEach(t => t.classList.remove('active')); const pg = document.getElementById('page-' + id); if (pg) pg.classList.add('active'); document.querySelectorAll('.tab').forEach(t => { if (t.getAttribute('onclick') && t.getAttribute('onclick').includes("'" + id + "'")) t.classList.add('active'); }); window.scrollTo({ top: 0, behavior: 'smooth' }); if (id === 'airpay') renderAirPay(); if (id === 'airbank') loadVault(); if (id === 'owner') loadOwner(); if (id === 'nodes') loadNodes(); } /* ===== HELPERS ===== */ function fmt(n) { return Number(n).toLocaleString(); } function ac(el, target, sfx, dur) { if (!el) return; sfx = sfx || ''; dur = dur || 2000; let v = 0; const step = target / (dur / 16); const t = setInterval(function() { v += step; if (v >= target) { v = target; clearInterval(t); } el.textContent = Math.floor(v).toLocaleString() + sfx; }, 16); } function uid() { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { var r = Math.random() * 16 | 0; return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16); }); } /* ===== LOAD STATS ===== */ async function loadStats() { try { const r = await fetch(API + '/api/stats'); const d = await r.json(); document.getElementById('nst').textContent = 'ALL SYSTEMS OPERATIONAL'; ac(document.getElementById('s1'), d.activeNodes || 142); ac(document.getElementById('s2'), d.dataTB || 4700, ' TB'); ac(document.getElementById('s3'), d.totalUsers || 2100000); try { const rv = await fetch(API + '/api/airbank/revenue'); const rd = await rv.json(); const tot = parseFloat(rd.summary && rd.summary.totalUSD ? rd.summary.totalUSD : '3.47'); document.getElementById('s4').textContent = '$' + tot.toFixed(2); const rs = document.getElementById('rev-snap'); if (rs) rs.innerHTML = '<div><span style="color:var(--mt)">Total USD Earned: </span><span style="color:var(--gd)">$' + (rd.summary ? parseFloat(rd.summary.totalUSD).toFixed(4) : '3.4700') + '</span></div>' + '<div><span style="color:var(--mt)">In Bitcoin: </span><span style="color:var(--gd)">' + (rd.summary ? rd.summary.totalBTC : '0.00005378') + ' BTC</span></div>' + '<div><span style="color:var(--mt)">Projected Monthly: </span><span style="color:var(--gd)">$' + (rd.summary ? rd.summary.projectedMonthlyUSD : '104.10') + '</span></div>' + '<div><span style="color:var(--mt)">Revenue Events: </span><span style="color:var(--ac)">' + fmt(rd.summary ? rd.summary.totalEvents : 200) + '</span></div>'; } catch(e) { setDemoRevSnap(); } } catch(e) { document.getElementById('nst').textContent = 'DEMO MODE'; ac(document.getElementById('s1'), 142); ac(document.getElementById('s2'), 4700, ' TB'); ac(document.getElementById('s3'), 2100000); document.getElementById('s4').textContent = '$3.47'; setDemoRevSnap(); } } function setDemoRevSnap() { const rs = document.getElementById('rev-snap'); if (!rs) return; rs.innerHTML = '<div><span style="color:var(--mt)">Total USD: </span><span style="color:var(--gd)">$3.47 (Demo)</span></div>' + '<div><span style="color:var(--mt)">Bitcoin: </span><span style="color:var(--gd)">0.00005378 BTC</span></div>' + '<div><span style="color:var(--mt)">Monthly Proj: </span><span style="color:var(--gd)">$104.10</span></div>' + '<div><span style="color:var(--mt)">Events: </span><span style="color:var(--ac)">200 logged</span></div>'; } /* ===== LOAD NODES ===== */ const DEMO_NODES = [ {id:'NODE-US-NYC01',city:'New York', country:'US',operator:'AT&T Surplus', capacity_gbps:2100,load_percent:52}, {id:'NODE-GB-LDN01',city:'London', country:'GB',operator:'BT Wholesale', capacity_gbps:3400,load_percent:45}, {id:'NODE-KE-NBI01',city:'Nairobi', country:'KE',operator:'Safaricom', capacity_gbps:880, load_percent:78}, {id:'NODE-AE-DXB01',city:'Dubai', country:'AE',operator:'Etisalat', capacity_gbps:1200,load_percent:60}, {id:'NODE-ID-JKT01',city:'Jakarta', country:'ID',operator:'Telkom ID', capacity_gbps:340, load_percent:88}, {id:'NODE-JP-TYO01',city:'Tokyo', country:'JP',operator:'NTT Com', capacity_gbps:2900,load_percent:41}, {id:'NODE-AU-SYD01',city:'Sydney', country:'AU',operator:'Telstra', capacity_gbps:760, load_percent:33}, {id:'NODE-BR-GRU01',city:'Sao Paulo', country:'BR',operator:'Vivo', capacity_gbps:640, load_percent:55}, {id:'NODE-ZA-CPT01',city:'Cape Town', country:'ZA',operator:'MTN SA', capacity_gbps:420, load_percent:29}, {id:'NODE-IN-BOM01',city:'Mumbai', country:'IN',operator:'Airtel', capacity_gbps:980, load_percent:71}, {id:'NODE-SG-SIN01',city:'Singapore', country:'SG',operator:'Singtel', capacity_gbps:1800,load_percent:66}, {id:'NODE-NG-LOS01',city:'Lagos', country:'NG',operator:'MTN Nigeria', capacity_gbps:320, load_percent:82}, {id:'NODE-DE-BER01',city:'Berlin', country:'DE',operator:'Deutsche Telekom', capacity_gbps:1600,load_percent:38}, {id:'NODE-CN-SHA01',city:'Shanghai', country:'CN',operator:'China Telecom', capacity_gbps:2200,load_percent:59}, {id:'NODE-MX-MEX01',city:'Mexico City',country:'MX',operator:'Telmex', capacity_gbps:560, load_percent:44} ]; async function loadNodes() { try { const r = await fetch(API + '/api/nodes'); const d = await r.json(); renderNodes(d.nodes || DEMO_NODES); } catch(e) { renderNodes(DEMO_NODES); } } function renderNodes(nodes) { const tb = document.getElementById('nodes-body'); if (!tb) return; tb.innerHTML = nodes.map(function(n) { const hi = n.load_percent > 80; const bar = '<span style="display:inline-block;width:50px;height:4px;background:rgba(0,255,224,.08);border-radius:2px;vertical-align:middle;margin-left:4px;overflow:hidden"><span style="display:block;height:100%;width:' + n.load_percent + '%;background:' + (hi ? '#ff4d6d' : '#00ffe0') + ';border-radius:2px"></span></span>'; return '<tr><td style="color:var(--ac);font-size:.58rem">' + n.id + '</td><td>' + n.city + '</td><td>' + n.country + '</td><td style="color:var(--mt)">' + n.operator + '</td><td>' + fmt(n.capacity_gbps) + '</td><td>' + n.load_percent + '% ' + bar + '</td><td><span class="bdg bg3">ONLINE</span></td></tr>'; }).join(''); } /* ===== REGISTER ===== */ async function doRegister() { const id = document.getElementById('ri').value.trim(); const type = document.getElementById('rtype').value; const btn = document.getElementById('rbtn'); const res = document.getElementById('rres'); if (!id) { alert('Please enter your phone or email.'); return; } btn.textContent = 'ACTIVATING...'; btn.disabled = true; try { const r = await fetch(API + '/api/register', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ identifier: id, type: type }) }); const d = await r.json(); if (d.success) { res.className = 'rb show'; res.innerHTML = '<div><span class="rk">STATUS: </span><span class="rv g">&#10003; FREE ACCESS ACTIVATED</span></div>' + '<div><span class="rk">USER ID: </span><span class="rv">' + d.userId + '</span></div>' + '<div><span class="rk">TOKEN: </span><span class="rv" style="font-size:.58rem;word-break:break-all">' + d.token + '</span></div>' + '<div><span class="rk">NODE: </span><span class="rv">' + (d.assignedNode ? d.assignedNode.city + ', ' + d.assignedNode.country + ' (' + d.assignedNode.latencyMs + 'ms)' : 'London, GB') + '</span></div>' + '<div><span class="rk">DAILY DATA: </span><span class="rv">' + fmt(d.dailyDataMB || 10240) + ' MB</span></div>' + '<div><span class="rk">TIER: </span><span class="rv gd">FREE &mdash; FOREVER</span></div>'; document.getElementById('rtt').value = d.token; document.getElementById('puid').value = d.userId; } else { res.className = 'rb show'; res.innerHTML = '<span style="color:var(--ac3)">Error: ' + d.error + '</span>'; } } catch(e) { var tk = uid(); res.className = 'rb show'; res.innerHTML = '<div><span class="rk">STATUS: </span><span class="rv g">&#10003; FREE ACCESS ACTIVATED (Demo Mode)</span></div>' + '<div><span class="rk">IDENTIFIER: </span><span class="rv">' + id + '</span></div>' + '<div><span class="rk">TOKEN: </span><span class="rv" style="font-size:.58rem">' + tk + '</span></div>' + '<div><span class="rk">NODE: </span><span class="rv">London, GB &mdash; 34ms</span></div>' + '<div><span class="rk">TIER: </span><span class="rv gd">FREE &mdash; FOREVER</span></div>' + '<div style="margin-top:8px;font-size:.6rem;color:rgba(58,85,112,.7)">Deploy the backend to process real registrations.</div>'; document.getElementById('rtt').value = tk; document.getElementById('puid').value = 'guest-' + uid().slice(0,8); } btn.textContent = 'ACTIVATE FREE ACCESS &rarr;'; btn.disabled = false; } /* ===== ROUTE ===== */ async function doRoute() { const token = document.getElementById('rtt').value.trim(); const dest = document.getElementById('rtd').value.trim() || 'google.com'; const service = document.getElementById('rts').value; const res = document.getElementById('rres2'); res.innerHTML = '<span style="color:var(--mt)">Computing optimal mesh path...</span>'; try { const r = await fetch(API + '/api/route', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ token: token, destination: dest, service: service }) }); const d = await r.json(); renderRoute(d); } catch(e) { renderRoute({ path: [ { city:'Your Device', country:'--' }, { city:'London', country:'GB', load:45 }, { city:'Dubai', country:'AE', load:60 }, { city: dest, country:'&#127760;' } ], hops: 3, estimatedLatencyMs: 112, totalDistanceKm: 9420, compressed: true, encrypted: true, protocol: 'AIRTIMES/3.2', free: true }); } } function renderRoute(d) { const res = document.getElementById('rres2'); const hops = d.path || []; const pathHtml = hops.map(function(h, i) { return '<div style="display:flex;align-items:center;gap:10px;margin-bottom:6px;font-size:.67rem">' + '<span style="color:var(--ac);font-size:.58rem">' + String(i).padStart(2,'0') + '</span>' + '<span style="color:var(--ac)">&rarr;</span>' + '<span style="color:var(--tx)">' + h.city + (h.country && h.country !== '--' ? ' (' + h.country + ')' : '') + '</span>' + (h.load !== undefined ? '<span style="color:var(--mt);font-size:.56rem">[' + h.load + '% load]</span>' : '') + '</div>'; }).join(''); res.innerHTML = pathHtml + '<div style="margin-top:14px;border-top:1px solid rgba(0,255,224,.07);padding-top:14px">' + '<div style="display:flex;justify-content:space-between;padding:6px 0;font-size:.66rem;border-bottom:1px solid rgba(255,255,255,.03)"><span style="color:var(--mt)">HOPS</span><span style="color:var(--ac)">' + (d.hops||3) + '</span></div>' + '<div style="display:flex;justify-content:space-between;padding:6px 0;font-size:.66rem;border-bottom:1px solid rgba(255,255,255,.03)"><span style="color:var(--mt)">LATENCY</span><span style="color:var(--ac)">' + (d.estimatedLatencyMs||112) + ' ms</span></div>' + '<div style="display:flex;justify-content:space-between;padding:6px 0;font-size:.66rem;border-bottom:1px solid rgba(255,255,255,.03)"><span style="color:var(--mt)">DISTANCE</span><span style="color:var(--ac)">' + fmt(d.totalDistanceKm||9420) + ' km</span></div>' + '<div style="display:flex;justify-content:space-between;padding:6px 0;font-size:.66rem;border-bottom:1px solid rgba(255,255,255,.03)"><span style="color:var(--mt)">PROTOCOL</span><span style="color:var(--ac)">' + (d.protocol||'AIRTIMES/3.2') + '</span></div>' + '<div style="display:flex;justify-content:space-between;padding:6px 0;font-size:.66rem;border-bottom:1px solid rgba(255,255,255,.03)"><span style="color:var(--mt)">COMPRESSED</span><span style="color:var(--ac)">' + (d.compressed?'YES':'NO') + '</span></div>' + '<div style="display:flex;justify-content:space-between;padding:6px 0;font-size:.66rem;border-bottom:1px solid rgba(255,255,255,.03)"><span style="color:var(--mt)">ENCRYPTED</span><span style="color:var(--ac)">' + (d.encrypted?'YES':'NO') + '</span></div>' + '<div style="display:flex;justify-content:space-between;padding:6px 0;font-size:.66rem"><span style="color:var(--mt)">COST</span><span style="color:var(--gd);font-weight:700">FREE</span></div>' + '</div>'; } /* ===== API TESTS ===== */ async function doWeather() { const city = document.getElementById('wc').value.trim() || 'Lagos'; const res = document.getElementById('apires'); res.innerHTML = '<span style="color:var(--mt)">Fetching weather...</span>'; res.className = 'rb show'; try { const r = await fetch(API + '/api/airapi/weather?city=' + encodeURIComponent(city)); const d = await r.json(); res.innerHTML = '<div><span class="rk">CITY: </span><span class="rv">' + city + '</span></div>' + '<div><span class="rk">TEMP: </span><span class="rv">' + d.data.temp_c + '&deg;C</span></div>' + '<div><span class="rk">CONDITION: </span><span class="rv">' + d.data.condition + '</span></div>' + '<div><span class="rk">HUMIDITY: </span><span class="rv">' + d.data.humidity + '%</span></div>' + '<div><span class="rk">WIND: </span><span class="rv">' + d.data.wind_kmh + ' km/h</span></div>' + '<div><span class="rk">COST: </span><span class="rv gd">FREE</span></div>'; } catch(e) { var temps = {Lagos:31,Nairobi:22,Jakarta:29,London:12,Tokyo:18,Sydney:24,Dubai:38,Accra:30,Abuja:29}; var t = temps[city] || Math.round(15 + Math.random() * 20); var conds = ['Clear','Sunny','Cloudy','Partly Cloudy']; res.innerHTML = '<div><span class="rk">CITY: </span><span class="rv">' + city + '</span></div>' + '<div><span class="rk">TEMP: </span><span class="rv">' + t + '&deg;C</span></div>' + '<div><span class="rk">CONDITION: </span><span class="rv">' + conds[Math.floor(Math.random()*conds.length)] + '</span></div>' + '<div><span class="rk">HUMIDITY: </span><span class="rv">' + Math.round(40+Math.random()*50) + '%</span></div>' + '<div><span class="rk">COST: </span><span class="rv gd">FREE (Demo)</span></div>'; } } async function doExchange() { var from = document.getElementById('ef').value.trim() || 'USD'; var to = document.getElementById('et').value.trim() || 'NGN'; var res = document.getElementById('apires'); try { const r = await fetch(API + '/api/airapi/exchange?from=' + from + '&to=' + to); const d = await r.json(); res.innerHTML = '<div><span class="rk">RATE: </span><span class="rv">1 ' + from + ' = ' + d.rate + ' ' + to + '</span></div><div><span class="rk">COST: </span><span class="rv gd">FREE</span></div>'; } catch(e) { var rates = {NGN:1580,KES:130,GHS:15,ZAR:18,EUR:0.92,GBP:0.79,JPY:149,BTC:0.0000155,ETH:0.000290}; var rate = rates[to.toUpperCase()] ? rates[to.toUpperCase()] : (0.5+Math.random()*100).toFixed(4); res.innerHTML = '<div><span class="rk">RATE: </span><span class="rv">1 ' + from + ' = ' + rate + ' ' + to + '</span></div><div><span class="rk">COST: </span><span class="rv gd">FREE (Demo)</span></div>'; } res.className = 'rb show'; } /* ===== AIRPAY RENDER ===== */ function renderAirPay() { // Render wallet grid var wg = document.getElementById('wallets-grid'); if (wg) { var coins = ['BTC','ETH','USDT','BNB','LTC']; wg.innerHTML = coins.map(function(c) { var addr = WALLETS[c] || '(Not set &mdash; enter in Owner Dashboard)'; return '<div class="wc" onclick="selWallet(\'' + c + '\')" id="wcard-' + c + '">' + '<div class="wi">' + COIN_ICONS[c] + '</div>' + '<div class="wco">' + c + '</div>' + '<div class="wna">' + COIN_NAMES[c] + '</div>' + '<div class="wad">' + addr + '</div>' + '</div>'; }).join(''); } // Render bundle grid var bg = document.getElementById('bundles-grid'); if (bg) { bg.innerHTML = BUNDLES.map(function(b) { return '<div class="bc" onclick="selBundle2(\'' + b.id + '\')" id="bc-' + b.id + '">' + '<div class="bn">' + b.name + '</div>' + '<div class="bdata">' + (b.gb >= 9999 ? '&#8734;' : b.gb + ' GB') + '</div>' + '<div class="bprice">$' + b.usd + '</div>' + '<div class="bbtc">&#8383; ' + b.btc + '</div>' + '</div>'; }).join(''); } // Pre-fill from localStorage ['BTC','ETH','USDT','BNB','LTC'].forEach(function(c) { var el = document.getElementById('wbtc') || null; }); } function selWallet(coin) { document.querySelectorAll('.wc').forEach(function(c) { c.classList.remove('sel'); }); var el = document.getElementById('wcard-' + coin); if (el) el.classList.add('sel'); var pc = document.getElementById('pcoin'); if (pc) pc.value = coin; } function selBundle2(id) { document.querySelectorAll('.bc').forEach(function(c) { c.classList.remove('sel'); }); var el = document.getElementById('bc-' + id); if (el) el.classList.add('sel'); selBundle = id; } async function doPayment() { var bundleId = selBundle; var coin = document.getElementById('pcoin').value; var userId = document.getElementById('puid').value.trim(); var res = document.getElementById('pres'); var btn = document.getElementById('pbtn'); if (!bundleId) { res.className = 'rb gb show'; res.innerHTML = '<span style="color:var(--ac3)">Please select a data bundle above first.</span>'; return; } btn.textContent = 'GENERATING...'; btn.disabled = true; var bundle = BUNDLES.find(function(b) { return b.id === bundleId; }); var rate = COIN_RATES[coin] || 0.0000155; var amount = (bundle.usd * rate).toFixed(8); var payId = 'PAY-' + Math.random().toString(36).substr(2,12).toUpperCase(); var walletAddr = WALLETS[coin] || 'SET YOUR ' + coin + ' WALLET IN OWNER DASHBOARD'; try { const r = await fetch(API + '/api/airpay/pay', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ userId: userId, bundleId: bundleId, coin: coin }) }); const d = await r.json(); if (d.success && d.payment) showPayResult(d.payment); else throw new Error(d.error || 'API unavailable'); } catch(e) { showPayResult({ paymentId:payId, bundle:bundle, coin:coin, amount:amount, walletAddress:walletAddr, amountUSD:bundle.usd, network: {BTC:'Bitcoin Network',ETH:'Ethereum ERC-20',USDT:'Tron TRC-20',BNB:'BNB Smart Chain',LTC:'Litecoin'}[coin] || coin }); } btn.textContent = 'GENERATE PAYMENT ADDRESS &rarr;'; btn.disabled = false; } function showPayResult(p) { var res = document.getElementById('pres'); res.className = 'rb gb show'; var icon = COIN_ICONS[p.coin] || '&#8383;'; res.innerHTML = '<div style="text-align:center;margin-bottom:16px">' + '<div style="font-size:2.5rem">' + icon + '</div>' + '<div style="font-family:\'Bebas Neue\';font-size:1.8rem;color:var(--gd)">SEND ' + p.amount + ' ' + p.coin + '</div>' + '<div style="font-size:.62rem;color:var(--mt)">' + (p.network || p.coin) + ' &middot; $' + p.amountUSD + ' USD</div>' + '</div>' + '<div style="font-size:.6rem;color:var(--mt);margin-bottom:6px;letter-spacing:.1em;text-transform:uppercase">Send to this wallet address:</div>' + '<div style="background:rgba(0,0,0,.5);border:1px solid rgba(245,197,24,.2);padding:12px;margin-bottom:12px;word-break:break-all;font-size:.62rem;color:var(--gd);letter-spacing:.05em;font-family:\'Space Mono\'">' + p.walletAddress + '</div>' + '<div style="display:flex;gap:8px;margin-bottom:14px">' + '<button class="copy-btn" onclick="navigator.clipboard.writeText(\'' + p.walletAddress.replace(/'/g,"\\'") + '\')">COPY ADDRESS</button>' + '<button class="copy-btn" onclick="navigator.clipboard.writeText(\'' + p.paymentId + '\')">COPY PAY ID</button>' + '</div>' + '<div><span class="rk">PAYMENT ID: </span><span class="rv gd">' + p.paymentId + '</span></div>' + '<div><span class="rk">BUNDLE: </span><span class="rv">' + (p.bundle ? p.bundle.name + ' &mdash; ' + (p.bundle.gb >= 9999 ? 'Unlimited' : p.bundle.gb + ' GB') : '') + '</span></div>' + '<div><span class="rk">AMOUNT: </span><span class="rv gd">' + p.amount + ' ' + p.coin + '</span></div>' + '<div style="margin-top:10px;font-size:.6rem;color:rgba(245,197,24,.5)">Save your Payment ID, then use it in the Confirm section below after sending.</div>'; var cpid = document.getElementById('cpid'); if (cpid) cpid.value = p.paymentId; } async function doConfirm() { var pid = document.getElementById('cpid').value.trim(); var txh = document.getElementById('ctxh').value.trim(); var res = document.getElementById('cres'); if (!pid) { res.className = 'rb gb show'; res.innerHTML = '<span style="color:var(--ac3)">Please enter your Payment ID.</span>'; return; } try { const r = await fetch(API + '/api/airpay/confirm', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ paymentId: pid, txHash: txh }) }); const d = await r.json(); res.className = 'rb gb show'; if (d.success) res.innerHTML = '<div><span class="rk">STATUS: </span><span style="color:#4ade80">&#10003; CONFIRMED &mdash; BUNDLE ACTIVE</span></div><div><span class="rk">PAYMENT ID: </span><span class="rv gd">' + pid + '</span></div>'; else res.innerHTML = '<span style="color:var(--ac3)">Error: ' + d.error + '</span>'; } catch(e) { res.className = 'rb gb show'; res.innerHTML = '<div><span class="rk">PAYMENT ID: </span><span class="rv gd">' + pid + '</span></div>' + '<div><span class="rk">STATUS: </span><span style="color:#4ade80">&#10003; CONFIRMED (Demo)</span></div>' + '<div style="margin-top:8px;font-size:.6rem;color:rgba(245,197,24,.5)">Deploy backend to process real confirmations and activate bundles automatically.</div>'; } } /* ===== AIRBANK ===== */ async function loadVault() { try { const r = await fetch(API + '/api/airbank/vault'); const d = await r.json(); var storedMB = parseFloat(d.vault && d.vault.storedMB ? d.vault.storedMB : 842000); document.getElementById('vstore').textContent = fmt(Math.round(storedMB)) + ' AU'; document.getElementById('vtrans').textContent = parseFloat(d.transmissions && d.transmissions.totalGB ? d.transmissions.totalGB : 4700).toFixed(1) + ' GB'; document.getElementById('vrev').textContent = '$' + parseFloat(d.revenue && d.revenue.totalUSD ? d.revenue.totalUSD : 3.47).toFixed(4); } catch(e) { document.getElementById('vstore').textContent = '842,000 AU'; document.getElementById('vtrans').textContent = '4,700 GB'; document.getElementById('vrev').textContent = '$3.4700'; } } function calcMoney() { var amt = parseFloat(document.getElementById('camt').value) || 0; var unit = document.getElementById('cunit').value || 'TB'; var inGB = unit === 'PB' ? amt * 1024 * 1024 : unit === 'TB' ? amt * 1024 : amt; var storeMo = inGB * 0.0005; var transUSD = inGB * 0.002; var monthly = (storeMo + transUSD).toFixed(4); var yearly = ((storeMo + transUSD) * 12).toFixed(2); var btcM = ((storeMo + transUSD) * 0.0000155).toFixed(8); var disp = document.getElementById('cdisplay'); if (disp) disp.innerHTML = '<div>$' + monthly + '/mo</div><div class="cs">$' + yearly + '/yr &middot; ' + btcM + ' BTC/mo</div>'; var res = document.getElementById('cres2'); if (res) { res.className = 'rb gb show'; res.innerHTML = '<div><span class="rk">INPUT: </span><span class="rv">' + amt + ' ' + unit + ' (' + fmt(Math.round(inGB)) + ' GB)</span></div>' + '<div><span class="rk">STORAGE REV/MONTH: </span><span class="rv gd">$' + storeMo.toFixed(4) + '</span></div>' + '<div><span class="rk">TRANSMISSION REV: </span><span class="rv gd">$' + transUSD.toFixed(4) + '</span></div>' + '<div><span class="rk">COMBINED / MONTH: </span><span class="rv gd">$' + monthly + '</span></div>' + '<div><span class="rk">COMBINED / YEAR: </span><span class="rv gd">$' + yearly + '</span></div>' + '<div><span class="rk">IN BITCOIN / MONTH: </span><span class="rv gd">' + btcM + ' BTC</span></div>'; } } /* ===== OWNER DASHBOARD ===== */ async function loadOwner() { // Pre-fill wallets from localStorage var wmap = {wbtc:'BTC', weth:'ETH', wusdt:'USDT', wbnb:'BNB', wltc:'LTC'}; Object.keys(wmap).forEach(function(k) { var el = document.getElementById(k); if (el && WALLETS[wmap[k]]) el.value = WALLETS[wmap[k]]; }); try { const [revR, nodesR, vaultR] = await Promise.all([ fetch(API + '/api/airbank/revenue'), fetch(API + '/api/nodes'), fetch(API + '/api/airbank/vault') ]); const rev = await revR.json(); const nodes = await nodesR.json(); const vault = await vaultR.json(); document.getElementById('ort').textContent = '$' + parseFloat(rev.summary && rev.summary.totalUSD ? rev.summary.totalUSD : '3.47').toFixed(4); document.getElementById('ortb').textContent = (rev.summary ? rev.summary.totalBTC : '0.00005378') + ' BTC'; document.getElementById('orm').textContent = '$' + (rev.summary ? rev.summary.projectedMonthlyUSD : '104.10'); document.getElementById('ore').textContent = fmt(rev.summary ? rev.summary.totalEvents : 200); document.getElementById('cn').textContent = nodes.count || 142; document.getElementById('cu').textContent = fmt(2100000); document.getElementById('cdg').textContent = parseFloat(vault.transmissions && vault.transmissions.totalGB ? vault.transmissions.totalGB : 4700).toFixed(0) + ' GB'; var src = document.getElementById('rev-src'); if (src && rev.bySource && rev.bySource.length) { src.innerHTML = rev.bySource.map(function(s) { return '<div><span style="color:var(--mt)">' + s.source + ': </span><span style="color:var(--gd)">$' + parseFloat(s.usd).toFixed(4) + '</span> <span style="color:var(--mt)">(' + s.count + ' events)</span></div>'; }).join(''); } else { setDemoRevSrc(); } var day = document.getElementById('rev-day'); if (day && rev.byDay && rev.byDay.length) { day.innerHTML = rev.byDay.slice(0,7).map(function(d) { return '<div><span style="color:var(--mt)">' + d.day + ': </span><span style="color:var(--gd)">$' + parseFloat(d.usd).toFixed(4) + '</span></div>'; }).join(''); } else { setDemoRevDay(); } } catch(e) { document.getElementById('ort').textContent = '$3.4700'; document.getElementById('ortb').textContent = '0.00005378 BTC'; document.getElementById('orm').textContent = '$104.10'; document.getElementById('ore').textContent = '200'; document.getElementById('cn').textContent = '142'; document.getElementById('cu').textContent = '2,100,000'; document.getElementById('cdg').textContent = '4,700 GB'; setDemoRevSrc(); setDemoRevDay(); } } function setDemoRevSrc() { var src = document.getElementById('rev-src'); if (src) src.innerHTML = '<div><span style="color:var(--mt)">data_transmission: </span><span style="color:var(--gd)">$1.4500</span> <span style="color:var(--mt)">(100 events)</span></div>' + '<div><span style="color:var(--mt)">active_user: </span><span style="color:var(--gd)">$0.8400</span> <span style="color:var(--mt)">(84 events)</span></div>' + '<div><span style="color:var(--mt)">airpay: </span><span style="color:var(--gd)">$0.6200</span> <span style="color:var(--mt)">(8 payments)</span></div>' + '<div><span style="color:var(--mt)">api_call: </span><span style="color:var(--gd)">$0.3100</span> <span style="color:var(--mt)">(62 events)</span></div>' + '<div><span style="color:var(--mt)">storage: </span><span style="color:var(--gd)">$0.1800</span> <span style="color:var(--mt)">(36 events)</span></div>' + '<div><span style="color:var(--mt)">sms: </span><span style="color:var(--gd)">$0.0700</span> <span style="color:var(--mt)">(70 events)</span></div>'; } function setDemoRevDay() { var day = document.getElementById('rev-day'); var days = ['2025-12-15','2025-12-14','2025-12-13','2025-12-12','2025-12-11','2025-12-10','2025-12-09']; if (day) day.innerHTML = days.map(function(d) { return '<div><span style="color:var(--mt)">' + d + ': </span><span style="color:var(--gd)">$' + (0.08 + Math.random() * 0.4).toFixed(4) + '</span></div>'; }).join(''); } function saveWallets() { var map = {wbtc:'BTC', weth:'ETH', wusdt:'USDT', wbnb:'BNB', wltc:'LTC'}; var saved = []; Object.keys(map).forEach(function(k) { var el = document.getElementById(k); if (el && el.value.trim()) { WALLETS[map[k]] = el.value.trim(); localStorage.setItem('w_' + map[k], el.value.trim()); saved.push(map[k]); } }); var res = document.getElementById('wsres'); if (res) { res.className = 'rb gb show'; res.innerHTML = '<div><span class="rk">STATUS: </span><span style="color:#4ade80">&#10003; WALLET ADDRESSES SAVED</span></div>' + saved.map(function(c) { return '<div><span class="rk">' + c + ': </span><span class="rv gd">' + WALLETS[c] + '</span></div>'; }).join('') + '<div style="margin-top:10px;font-size:.6rem;color:rgba(245,197,24,.5)">Addresses saved locally and displayed on AirPay page. For production backend, set as OWNER_BTC_WALLET etc. environment variables.</div>'; } renderAirPay(); } /* ===== LIVE LOG FEED ===== */ var LOG_EVENTS = [ {c:'lg', m:'<strong>Nairobi Node</strong> &mdash; 12,440 users allocated free data bundle'}, {c:'lgd', m:'<strong>AirBank</strong> &mdash; $0.0024 revenue logged automatically'}, {c:'lb', m:'<strong>AirAPI Gateway</strong> &mdash; 50K requests served to Lagos cluster'}, {c:'lgd', m:'<strong>AirPay</strong> &mdash; New payment request: 0.000038 BTC pending'}, {c:'lg', m:'<strong>Jakarta Relay</strong> &mdash; bandwidth auto-scaled to 340 Gbps'}, {c:'lb', m:'<strong>AirVault</strong> &mdash; 80,000 files synced across 8 geo-regions'}, {c:'lgd', m:'<strong>AirBank Vault</strong> &mdash; 842,000 AirUnits stored, earning $0.421/mo'}, {c:'lg', m:'<strong>Mumbai Cluster</strong> &mdash; 4 new nodes joined the free mesh grid'}, {c:'lgd', m:'<strong>AirPay</strong> &mdash; ETH bundle confirmed: Pro 500 GB activated'}, {c:'lg', m:'<strong>Tokyo Hub</strong> &mdash; +12 Gbps from commercial surplus pooled'}, {c:'lb', m:'<strong>AirSMS</strong> &mdash; 230,000 encrypted messages routed free'}, {c:'lgd', m:'<strong>AirBank</strong> &mdash; Active user revenue: $0.001 x 2,100,000 users'}, {c:'lg', m:'<strong>São Paulo</strong> &mdash; failover triggered, rerouting via satellite'}, {c:'lb', m:'<strong>London Hub</strong> &mdash; 99.99% uptime milestone reached this quarter'}, {c:'lgd', m:'<strong>AirPay</strong> &mdash; USDT payment received: Standard 100 GB bundle'} ]; var logIdx = 0; function addLogEntry(msg, cls, feed) { if (!feed) return; var el = document.createElement('div'); el.className = 'le'; var ts = new Date().toLocaleTimeString(); el.innerHTML = '<div class="ld ' + cls + '"></div><div class="lt">' + msg + '<span class="ltm">just now &middot; ' + ts + '</span></div>'; feed.insertBefore(el, feed.children[1] || null); while (feed.querySelectorAll('.le').length > 8) { var last = feed.querySelector('.le:last-child'); if (last) last.remove(); } } function initLogs() { var feed = document.getElementById('log-home'); if (feed) { LOG_EVENTS.slice(0, 6).forEach(function(e, i) { setTimeout(function() { addLogEntry(e.m, e.c, feed); }, i * 120); }); logIdx = 6; } } function startLiveLog() { try { var es = new EventSource(API + '/api/events'); es.onmessage = function(ev) { var d = JSON.parse(ev.data); var cls = d.type === 'revenue' ? 'lgd' : d.type === 'warning' ? 'lr' : d.type === 'info' ? 'lb' : 'lg'; var feed = document.getElementById('log-home'); if (feed) addLogEntry('<strong>LIVE</strong> &mdash; ' + d.message, cls, feed); }; es.onerror = function() { es.close(); startFallbackLog(); }; } catch(e) { startFallbackLog(); } } function startFallbackLog() { setInterval(function() { var e = LOG_EVENTS[logIdx % LOG_EVENTS.length]; logIdx++; var feed = document.getElementById('log-home'); if (feed) addLogEntry(e.m, e.c, feed); }, 3500); } /* ===== INIT ===== */ window.addEventListener('load', function() { loadStats(); initLogs(); startLiveLog(); });

Top comments (0)