chore: add kron and sdwan demo apps
This commit is contained in:
parent
c75c3485af
commit
b4e3696a3c
13 changed files with 271 additions and 0 deletions
2
kron/.gitignore
vendored
Normal file
2
kron/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
node_modules/
|
||||
dev-dist/
|
||||
1
kron/dist/assets/index-DDORw3oI.css
vendored
Normal file
1
kron/dist/assets/index-DDORw3oI.css
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
:root{--bg: #0a0a0f;--surface: #12121a;--border: #1e1e2e;--text: #c8c8d4;--muted: #5a5a72;--green: #00e676;--red: #ff3b30;--amber: #ff9500;--blue: #0066ff;--radius: 12px;--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--mono: "SF Mono", "Fira Code", "JetBrains Mono", "Courier New", monospace}*,*:before,*:after{box-sizing:border-box;margin:0;padding:0}html,body,#root{height:100%}body{background:var(--bg);color:var(--text);font-family:var(--font);-webkit-font-smoothing:antialiased;-webkit-tap-highlight-color:transparent;overflow:hidden}.app-container{height:100%;display:flex;flex-direction:column;max-width:480px;margin:0 auto}.location-screen{height:100%;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px 24px;text-align:center}.loc-icon{font-size:40px;margin-bottom:8px}.loc-title{font-size:24px;font-weight:700;color:var(--text);letter-spacing:-.02em;margin-bottom:4px}.loc-sub{font-size:13px;color:var(--muted);margin-bottom:32px}.loc-list{width:100%;max-width:320px;display:flex;flex-direction:column;gap:10px}.loc-btn{display:flex;align-items:center;gap:12px;width:100%;padding:14px 16px;border-radius:12px;background:var(--surface);border:1px solid var(--border);color:var(--text);font-size:15px;font-weight:500;cursor:pointer;text-align:left;transition:border-color .2s,background .2s;font-family:var(--font)}.loc-btn:active{background:#1a1a2a;border-color:var(--blue);transform:scale(.98)}.loc-dot{width:8px;height:8px;border-radius:50%;background:var(--muted);flex-shrink:0}.loc-footer{margin-top:auto;font-size:9px;color:var(--muted);letter-spacing:.2em;padding-bottom:12px}.auth-panel{padding:10px 16px;background:var(--surface);border-bottom:1px solid var(--border);display:flex;align-items:center;gap:12px;flex-shrink:0}.location-group{flex:1;min-width:0}.auth-label{font-size:9px;color:var(--muted);text-transform:uppercase;letter-spacing:.12em;margin-bottom:2px;font-weight:600}.loc-display{display:flex;align-items:center;gap:8px;font-size:14px;font-weight:600;color:var(--text)}.loc-display .loc-dot{background:var(--green)}.otp-box{flex-shrink:0;width:120px;background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:8px;text-align:center}.otp-label{font-size:7px;color:var(--muted);text-transform:uppercase;letter-spacing:.12em;font-weight:600;margin-bottom:3px}.otp-code{font-family:var(--mono);font-size:18px;font-weight:700;color:var(--green);letter-spacing:.1em}.otp-timer{margin-top:5px;height:2px;background:var(--border);border-radius:2px;overflow:hidden}.otp-timer-bar{height:100%;background:var(--blue);border-radius:2px;transition:width 1s linear}.terminal-panel{flex:1;display:flex;flex-direction:column;background:#0d0d14;min-height:0}.terminal-header{display:flex;align-items:center;gap:6px;padding:7px 12px;background:#16161e;border-bottom:1px solid var(--border);flex-shrink:0}.terminal-dot{width:9px;height:9px;border-radius:50%}.terminal-title{margin-left:auto;font-size:9px;color:var(--muted);font-family:var(--mono)}.terminal-body{flex:1;overflow-y:auto;padding:12px;font-family:var(--mono);font-size:13px;line-height:1.6;-webkit-overflow-scrolling:touch}.t-line{white-space:pre-wrap;word-break:break-word;min-height:1.4em}.t-green{color:var(--green)}.t-red{color:var(--red)}.t-amber{color:var(--amber)}.t-prompt{color:var(--green);white-space:pre}.t-input{background:none;border:none;color:var(--text);font-family:var(--mono);font-size:13px;outline:none;caret-color:var(--green);flex:1;min-width:0}.t-input::placeholder{color:var(--muted);opacity:.5;font-size:11px}.t-line form{display:flex;align-items:center;gap:0}.cursor-blink{color:var(--green);animation:blink 1s step-end infinite}@keyframes blink{0%,to{opacity:1}50%{opacity:0}}.matrix-canvas{position:fixed;top:0;right:0;bottom:0;left:0;z-index:100;pointer-events:none}.access-banner{position:fixed;top:0;right:0;bottom:0;left:0;z-index:50;background:#000000f0;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;text-align:center;animation:fadeIn .6s ease}.access-icon{font-size:48px;margin-bottom:12px;animation:float 2s ease-in-out infinite}.access-title{font-size:24px;font-weight:700;color:var(--green);letter-spacing:.05em;margin-bottom:6px}.access-sub{font-size:12px;color:var(--muted);margin-bottom:24px}.access-detail{font-size:12px;color:var(--text);font-family:var(--mono);line-height:2;text-align:left;margin-bottom:32px}.reset-btn{padding:14px 40px;border-radius:10px;background:var(--green);color:#000;font-weight:700;font-size:15px;border:none;cursor:pointer;font-family:var(--font)}.reset-btn:active{transform:scale(.97)}@keyframes fadeIn{0%{opacity:0}to{opacity:1}}@keyframes float{0%,to{transform:translateY(0)}50%{transform:translateY(-6px)}}
|
||||
40
kron/dist/assets/index-Djs4PpQW.js
vendored
Normal file
40
kron/dist/assets/index-Djs4PpQW.js
vendored
Normal file
File diff suppressed because one or more lines are too long
14
kron/dist/index.html
vendored
Normal file
14
kron/dist/index.html
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en"><head>
|
||||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<meta name="theme-color" content="#0a0a0f"><meta name="apple-mobile-web-app-capable" content="yes">
|
||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||
<title>Kron PAM Vault Break</title>
|
||||
<script type="module" crossorigin src="/kron/assets/index-Djs4PpQW.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/kron/assets/index-DDORw3oI.css">
|
||||
<link rel="manifest" href="/kron/manifest.webmanifest"><script id="vite-plugin-pwa:register-sw" src="/kron/registerSW.js"></script></head><body>
|
||||
<div style="background:#0a0a0f; border-bottom:1px solid #1e1e2e; padding:5px 12px; font-size:12px;">
|
||||
<a href="/" style="color:#5a5a72; text-decoration:none;">← GITEX 2026 Hub</a>
|
||||
</div>
|
||||
<div id="root"></div>
|
||||
</body></html>
|
||||
1
kron/dist/manifest.webmanifest
vendored
Normal file
1
kron/dist/manifest.webmanifest
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
{"name":"Kron PAM Vault Break","short_name":"Kron Vault","description":"GITEX 2026 PAM security challenge","start_url":"/","display":"standalone","background_color":"#06060e","theme_color":"#06060e","lang":"en","scope":"/kron/","orientation":"portrait","icons":[{"src":"icon-192.png","sizes":"192x192","type":"image/png"},{"src":"icon-512.png","sizes":"512x512","type":"image/png"}]}
|
||||
1
kron/dist/registerSW.js
vendored
Normal file
1
kron/dist/registerSW.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
if('serviceWorker' in navigator) {window.addEventListener('load', () => {navigator.serviceWorker.register('/kron/sw.js', { scope: '/kron/' })})}
|
||||
1
kron/dist/sw.js
vendored
Normal file
1
kron/dist/sw.js
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
if(!self.define){let e,s={};const i=(i,n)=>(i=new URL(i+".js",n).href,s[i]||new Promise(s=>{if("document"in self){const e=document.createElement("script");e.src=i,e.onload=s,document.head.appendChild(e)}else e=i,importScripts(i),s()}).then(()=>{let e=s[i];if(!e)throw new Error(`Module ${i} didn’t register its module`);return e}));self.define=(n,r)=>{const t=e||("document"in self?document.currentScript.src:"")||location.href;if(s[t])return;let o={};const l=e=>i(e,t),d={module:{uri:t},exports:o,require:l};s[t]=Promise.all(n.map(e=>d[e]||l(e))).then(e=>(r(...e),o))}}define(["./workbox-9c191d2f"],function(e){"use strict";self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"registerSW.js",revision:"0ccfe96049cf135e9d3b1af97624b571"},{url:"index.html",revision:"6399a5aae2d506f7b9dcd626a16b4e00"},{url:"assets/index-Djs4PpQW.js",revision:null},{url:"assets/index-DDORw3oI.css",revision:null},{url:"manifest.webmanifest",revision:"dec3f83176afdc0af818b7d71a09b5d0"}],{}),e.cleanupOutdatedCaches(),e.registerRoute(new e.NavigationRoute(e.createHandlerBoundToURL("index.html")))});
|
||||
1
kron/dist/workbox-9c191d2f.js
vendored
Normal file
1
kron/dist/workbox-9c191d2f.js
vendored
Normal file
File diff suppressed because one or more lines are too long
1
sdwan/.gitignore
vendored
Normal file
1
sdwan/.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
node_modules/
|
||||
179
sdwan/dist/assets/index-d6HUX9kC.js
vendored
Normal file
179
sdwan/dist/assets/index-d6HUX9kC.js
vendored
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const i of document.querySelectorAll('link[rel="modulepreload"]'))a(i);new MutationObserver(i=>{for(const r of i)if(r.type==="childList")for(const o of r.addedNodes)o.tagName==="LINK"&&o.rel==="modulepreload"&&a(o)}).observe(document,{childList:!0,subtree:!0});function s(i){const r={};return i.integrity&&(r.integrity=i.integrity),i.referrerPolicy&&(r.referrerPolicy=i.referrerPolicy),i.crossOrigin==="use-credentials"?r.credentials="include":i.crossOrigin==="anonymous"?r.credentials="omit":r.credentials="same-origin",r}function a(i){if(i.ep)return;i.ep=!0;const r=s(i);fetch(i.href,r)}})();const N={mpls:20,internet:50,lte:60},E={mpls:.2,internet:.3,lte:.5};function P(e,t={}){return e.map(s=>{const a=t[s.id];return{...s,latencyMs:(a==null?void 0:a.latencyMs)??N[s.id]??100,packetLossPercent:(a==null?void 0:a.packetLossPercent)??E[s.id]??1}})}const C=100,x=1;function D(e){return e.latencyMs<=C&&e.packetLossPercent<=x}function W(e){return e.map(t=>({...t,isValid:D(t)}))}function O(e){return M(e.filter(t=>t.isValid))[0]}function R(e){return M(e)[0]}function M(e){return e.sort((t,s)=>{const a=t.packetLossPercent-s.packetLossPercent;return Math.abs(a)>.001?a:t.latencyMs-s.latencyMs})}function _(e){const{links:t,activeLinkId:s,degradationTicks:a}=e;if(t.filter(c=>c.isValid).length===0){const c=R(t);return{activeLinkId:c?c.id:null,systemState:"degraded",degradationTicks:a+1}}const r=O(t),o=t.find(c=>c.id===s);return!o||!o.isValid?{activeLinkId:r.id,systemState:"normal",degradationTicks:0}:{activeLinkId:o.id,systemState:"normal",degradationTicks:0}}const m=[{text:"What does SLA stand for in the context of SD-WAN?",options:["Service Level Agreement","Secure Link Access","System Latency Analysis","Serial Link Aggregation"],answer:0},{text:"What is the maximum acceptable latency threshold in this application?",options:["50 ms","80 ms","100 ms","150 ms"],answer:2},{text:"What is the maximum acceptable packet loss percentage per the SLA?",options:["0.5%","1%","2%","5%"],answer:1},{text:"How many WAN links does the SD-WAN Traffic Master simulate?",options:["2","3","4","5"],answer:1},{text:"Which WAN link type is the default primary path in the simulation?",options:["LTE","Internet","MPLS","Satellite"],answer:2},{text:"What happens when ALL links violate SLA thresholds?",options:["The application crashes","Traffic is silently dropped","The system enters Degraded Mode","All links are automatically reset"],answer:2},{text:"What is the full meaning of SD-WAN?",options:["Software-Defined Wide Area Network","Secure Digital Wireless Access Network","System-Defined Wide Access Node","Software-Driven Wide Application Network"],answer:0},{text:"MPLS, Internet and LTE are responsible for which type of SD-WAN tunnels?",options:["Underlay","Overlay","BIOS","Secure VPN"],answer:0},{text:"Which company powers this SD-WAN Traffic Master application?",options:["ARUBA","Juniper","Sechpoint","All of the above"],answer:2},{text:"What is the role of Business Intent Overlay in SD-WAN?",options:["Defines network policies based on business requirements and applications","Manages physical hardware connections","Encrypts data packets between endpoints","Monitors device CPU usage"],answer:0}];function S(){return m.length}const y=60;function A(){return{screen:"instructions",userName:"",currentQuestion:0,answers:[],timeRemaining:30,timerId:null,active:!1,attemptCount:0}}function F(e){return m[e]}function Q(e){let t=0;for(let s=0;s<m.length;s++)e[s]===m[s].answer&&t++;return{correct:t,total:m.length,percentage:Math.round(t/m.length*100)}}const $={mpls:"#8B5CF6",lte:"#EF4444",internet:"#F59E0B"};function T(e,t,s){return e<=t?"good":e<=s?"warn":"bad"}function B(e){return T(e,80,100)}function H(e){return T(e,.5,1)}function b(e){const{links:t,activeLinkId:s,systemState:a}=e;document.getElementById("app").innerHTML=`
|
||||
${U(a)}
|
||||
${V()}
|
||||
${a==="degraded"?Y():""}
|
||||
${K(t,s)}
|
||||
${J(t,s,a)}
|
||||
${Z()}
|
||||
`,G(e)}function U(e){return`
|
||||
<header class="header">
|
||||
<div>
|
||||
<h1>HPE Aruba SD-WAN Traffic Master</h1>
|
||||
<p class="header-subtitle">Real-time network traffic management simulation</p>
|
||||
<p class="header-powered">Powered by Sechpoint</p>
|
||||
<div class="header-thresholds">
|
||||
<span class="threshold-badge">Latency ≤ 100 ms</span>
|
||||
<span class="threshold-badge">Packet Loss ≤ 1%</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="header-badges">
|
||||
${e==="normal"?'<span class="badge badge-normal">Normal</span>':'<span class="badge badge-degraded">Degraded Mode</span>'}
|
||||
</div>
|
||||
</header>`}function V(){return`
|
||||
<div class="controls">
|
||||
<button class="quiz-btn" data-action="start-quiz">🧠 Take Quiz</button>
|
||||
</div>`}function Y(){return`
|
||||
<div class="degraded-warning">
|
||||
<h3>⚠ Degraded Mode — All links violate SLA thresholds</h3>
|
||||
<p>The best available link is kept active, but network performance is degraded. Monitor traffic closely.</p>
|
||||
</div>`}function K(e,t){return`<div class="link-cards">${e.map(a=>j(a,t)).join("")}</div>`}function j(e,t){const s=e.id===t;return`
|
||||
<div class="${["link-card",s?"active-link":"",!e.isValid&&!s?"blocked":""].filter(Boolean).join(" ")}" data-link-id="${e.id}">
|
||||
${s?'<span class="active-badge">Active</span>':""}
|
||||
|
||||
<div class="link-header">
|
||||
<span class="link-dot" style="background:${e.color}"></span>
|
||||
<span class="link-name">${e.name}</span>
|
||||
<span class="link-status ${e.isValid?"status-healthy":"status-blocked"}">
|
||||
${e.isValid?"Healthy":"Blocked"}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
${q("Latency",`${e.latencyMs} ms`,"100 ms",e.latencyMs,150,B(e.latencyMs),e.latencyMs>100?" ⚠":"",e.id,"latencyMs")}
|
||||
|
||||
${q("Packet Loss",`${e.packetLossPercent.toFixed(2)}%`,"1.00%",e.packetLossPercent,5,H(e.packetLossPercent),e.packetLossPercent>1?" ⚠":"",e.id,"packetLossPercent")}
|
||||
</div>`}function q(e,t,s,a,i,r,o,c,u){const l=Math.min(a/i*100,100);return`
|
||||
<div class="metric">
|
||||
<div class="metric-label">
|
||||
<span>${e}</span>
|
||||
<span class="metric-value ${r}">${t}${o}</span>
|
||||
</div>
|
||||
<div class="metric-bar">
|
||||
<div class="metric-bar-fill ${r}" style="width:${l}%"></div>
|
||||
</div>
|
||||
<div class="metric-limit">SLA limit: ${s}</div>
|
||||
<div class="metric-slider">
|
||||
<input
|
||||
type="range"
|
||||
min="0"
|
||||
max="${u==="latencyMs"?150:5}"
|
||||
step="${u==="latencyMs"?1:.01}"
|
||||
value="${a}"
|
||||
data-link-id="${c}"
|
||||
data-field="${u}"
|
||||
/>
|
||||
<label class="slider-label">${t}</label>
|
||||
</div>
|
||||
</div>`}function J(e,t,s){const a=t?e.find(c=>c.id===t):null,i=a?a.name:"—",r="",o=a?`background:${$[a.id]}22;color:${$[a.id]};`:"background:#374151;color:#9ca3af;";return`
|
||||
<div class="path-section">
|
||||
<h3>Active Path ${s==="degraded"?'<span class="badge badge-degraded" style="margin-left:8px">Degraded</span>':""}</h3>
|
||||
<div class="path-visual">
|
||||
<div class="path-endpoint">
|
||||
<span class="path-endpoint-icon">🏢</span>
|
||||
<span>Branch Office</span>
|
||||
</div>
|
||||
<div class="path-line"></div>
|
||||
<div class="path-link-badge ${r}" style="${o}">
|
||||
${i}
|
||||
</div>
|
||||
<div class="path-line"></div>
|
||||
<div class="path-endpoint">
|
||||
<span class="path-endpoint-icon">☁</span>
|
||||
<span>Data Center</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>`}function Z(){return`
|
||||
<div class="info-footer">
|
||||
<p><strong>SLA Thresholds:</strong> Latency ≤ 100 ms | Packet Loss ≤ 1%</p>
|
||||
<p><strong>Path Selection:</strong> Lowest packet loss → Lowest latency</p>
|
||||
<p><strong>Auto Failover:</strong> Traffic automatically shifts when active link violates SLA</p>
|
||||
<p><strong>Degraded Mode:</strong> When all links fail SLA, the best available link remains active</p>
|
||||
</div>`}function G(e){document.querySelectorAll("[data-action]").forEach(t=>{t.addEventListener("click",()=>{t.dataset.action==="start-quiz"&&e.onStartQuiz&&e.onStartQuiz()})}),document.querySelectorAll(".metric-slider input").forEach(t=>{t.addEventListener("input",s=>{const a=s.target.dataset.linkId,i=s.target.dataset.field,r=i==="latencyMs"?parseInt(s.target.value,10):parseFloat(s.target.value);e.onUpdateMetric&&e.onUpdateMetric(a,i,r)})})}function X(e,t){var r,o,c,u;const s=document.querySelector(".quiz-overlay");s&&s.remove();const a=document.createElement("div");a.className="quiz-overlay";const i=document.createElement("div");switch(i.className="quiz-container",e.screen){case"instructions":i.innerHTML=ee();break;case"name":i.innerHTML=te();break;case"quiz":i.innerHTML=ne(e);break;case"results":i.innerHTML=se(e);break}if(a.appendChild(i),document.body.appendChild(a),e.screen==="instructions"){const l=i.querySelector(".btn-primary");l&&l.addEventListener("click",t.onProceedToName),(r=i.querySelector(".btn-secondary"))==null||r.addEventListener("click",t.onCloseQuiz)}if(e.screen==="name"){const l=i.querySelector(".name-field"),v=i.querySelector(".name-error"),f=i.querySelector(".btn-primary"),z=()=>{const h=l.value.trim();if(!h){v.classList.add("visible");return}v.classList.remove("visible"),t.onStartQuiz(h)};f==null||f.addEventListener("click",z),l==null||l.addEventListener("keydown",h=>{h.key==="Enter"&&z()}),(o=i.querySelector(".btn-secondary"))==null||o.addEventListener("click",t.onCloseQuiz)}e.screen==="quiz"&&i.querySelectorAll(".quiz-option").forEach(l=>{l.addEventListener("click",()=>{const v=parseInt(l.dataset.optionIndex,10);t.onAnswerQuestion(e.currentQuestion,v)})}),e.screen==="results"&&((c=i.querySelector(".btn-primary"))==null||c.addEventListener("click",t.onCloseQuiz),(u=i.querySelector(".btn-secondary"))==null||u.addEventListener("click",t.onRestartQuiz))}function ee(){return`
|
||||
<div class="quiz-header">
|
||||
<h2>SD-WAN Knowledge Quiz</h2>
|
||||
<p>Test your understanding of the HPE Aruba SD-WAN Traffic Master</p>
|
||||
</div>
|
||||
<div class="quiz-body">
|
||||
<div class="study-note">
|
||||
⚠️ <strong>Important:</strong> Please study the application dashboard carefully
|
||||
before starting the quiz. Observe how the simulation works, understand the SLA
|
||||
thresholds, failover behavior, and the different link types. You will have
|
||||
<strong>30 seconds</strong> to answer each of the <strong>10 questions</strong>.
|
||||
</div>
|
||||
<div class="quiz-instructions">
|
||||
<h3>What you need to know:</h3>
|
||||
<ul>
|
||||
<li>SLA thresholds for latency and packet loss</li>
|
||||
<li>The three WAN link types and their roles</li>
|
||||
<li>Automatic path selection and failover rules</li>
|
||||
<li>Path selection and failover rules</li>
|
||||
<li>What happens during Degraded Mode</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="quiz-footer quiz-actions">
|
||||
<button class="btn-secondary">Cancel</button>
|
||||
<button class="btn-primary">Next →</button>
|
||||
</div>
|
||||
`}function te(){return`
|
||||
<div class="quiz-header">
|
||||
<h2>Enter Your Name</h2>
|
||||
<p>Your results will be saved under this name</p>
|
||||
</div>
|
||||
<div class="quiz-body">
|
||||
<input
|
||||
class="name-field"
|
||||
type="text"
|
||||
placeholder="Type your name here..."
|
||||
maxlength="40"
|
||||
autocomplete="off"
|
||||
/>
|
||||
<div class="name-error">Please enter your name to continue.</div>
|
||||
</div>
|
||||
<div class="quiz-footer quiz-actions">
|
||||
<button class="btn-secondary">Cancel</button>
|
||||
<button class="btn-primary">Start Quiz</button>
|
||||
</div>
|
||||
`}function ne(e){const t=e._questionData;if(!t)return"";const s=e.currentQuestion+1,a=e._totalQuestions,i=e.currentQuestion/a*100,r=e.timeRemaining<=10?" urgent":"",o=["A","B","C","D"];return`
|
||||
<div class="quiz-header">
|
||||
<h2>Question ${s} of ${a}</h2>
|
||||
<div class="quiz-name-badge">Player: ${e.userName}</div>
|
||||
</div>
|
||||
<div class="quiz-body">
|
||||
<div class="quiz-progress">
|
||||
<div class="quiz-progress-bar">
|
||||
<div class="quiz-progress-fill" style="width:${i}%"></div>
|
||||
</div>
|
||||
<div class="quiz-timer${r}">${e.timeRemaining}s</div>
|
||||
</div>
|
||||
<div class="quiz-question-text">${t.text}</div>
|
||||
<div class="quiz-options">
|
||||
${t.options.map((c,u)=>`
|
||||
<div class="quiz-option" data-option-index="${u}">
|
||||
<span class="option-letter">${o[u]}</span>
|
||||
<span>${c}</span>
|
||||
</div>
|
||||
`).join("")}
|
||||
</div>
|
||||
</div>
|
||||
`}function se(e){const t=e._results;if(!t)return"";const s=t.percentage>=y,a=!s&&e.attemptCount<2;let i="",r="",o="";return s?(i="Congratulations! You passed the quiz.",r='<div class="quiz-prize">🎉 Come to the <strong>Sechpoint Technologies</strong> booth to claim your prize!</div>'):a?(i=`You scored below ${y}%. You have one more attempt.`,o='<p class="quiz-retry-note">Study the dashboard carefully and try again.</p>'):i=`You scored below ${y}%. No more attempts allowed.`,`
|
||||
<div class="quiz-header">
|
||||
<h2>Quiz Complete!</h2>
|
||||
<div class="quiz-name-badge">${e.userName}</div>
|
||||
</div>
|
||||
<div class="quiz-body quiz-results">
|
||||
<div class="quiz-score-circle ${s?"":"quiz-fail"}">
|
||||
<span class="quiz-score-number">${t.percentage}%</span>
|
||||
<span class="quiz-score-label">SCORE</span>
|
||||
</div>
|
||||
<p class="quiz-score-detail">
|
||||
${t.correct} out of ${t.total} correct | Pass mark: ${y}% | Attempt ${e.attemptCount} of 2
|
||||
</p>
|
||||
<p class="quiz-feedback">${i}</p>
|
||||
${r}
|
||||
${o}
|
||||
</div>
|
||||
<div class="quiz-footer quiz-actions">
|
||||
${a?'<button class="btn-secondary">Retake Quiz</button>':""}
|
||||
<button class="btn-primary">Return to Dashboard</button>
|
||||
</div>
|
||||
`}const ie=[{id:"mpls",name:"MPLS",latencyMs:20,packetLossPercent:.2,color:"#8B5CF6"},{id:"lte",name:"LTE",latencyMs:60,packetLossPercent:.5,color:"#EF4444"},{id:"internet",name:"Internet",latencyMs:50,packetLossPercent:.3,color:"#F59E0B"}];let d={links:structuredClone(ie).map(e=>({...e,isValid:!0})),activeLinkId:"mpls",systemState:"normal",degradationTicks:0,tick:0,metricOverrides:{}},w=null;function I(){let e=P(d.links,d.metricOverrides);e=W(e);const t=_({...d,links:e});d={...d,links:e,activeLinkId:t.activeLinkId,systemState:t.systemState,degradationTicks:t.degradationTicks,tick:d.tick+1},b(k())}function k(){return{...d,onStartQuiz:ce,onUpdateMetric:ae}}function ae(e,t,s){d.metricOverrides={...d.metricOverrides,[e]:{...d.metricOverrides[e],[t]:s}},I()}function re(){w||(w=setInterval(I,1500))}let n=A();function p(){n.active&&requestAnimationFrame(()=>{n.active&&(n._questionData=F(n.currentQuestion),n._totalQuestions=S(),X(n,{onCloseQuiz:le,onProceedToName:()=>{n.screen="name",p()},onStartQuiz:e=>{n.userName=e,n.screen="quiz",n.currentQuestion=0,n.answers=[],n.timeRemaining=30,p(),g()},onAnswerQuestion:(e,t)=>{L(),n.answers[e]=t,n.currentQuestion<S()-1?(n.currentQuestion++,n.timeRemaining=30,p(),g()):(n.attemptCount++,n._results=Q(n.answers),n.screen="results",p())},onRestartQuiz:()=>{L();const e=n.userName,t=n.attemptCount;n=A(),n.active=!0,n.userName=e,n.attemptCount=t,n.screen="quiz",n.currentQuestion=0,n.answers=[],n.timeRemaining=30,p(),g()}}))})}function g(){L();let e=30;n.timeRemaining=e,n.timerId=setInterval(()=>{e--,n.timeRemaining=e,e<=0?(clearInterval(n.timerId),n.timerId=null,n.answers[n.currentQuestion]=-1,n.currentQuestion<S()-1?(n.currentQuestion++,n.timeRemaining=30,p(),g()):(n.attemptCount++,n._results=Q(n.answers),n.screen="results",p())):oe(e)},1e3)}function oe(e){const t=document.querySelector(".quiz-timer");t&&(t.textContent=`${e}s`,e<=10?t.classList.add("urgent"):t.classList.remove("urgent"))}function L(){n.timerId&&(clearInterval(n.timerId),n.timerId=null)}function ce(){n=A(),n.active=!0,n.screen="instructions",b(k()),p()}function le(){L(),n.active=!1;const e=document.querySelector(".quiz-overlay");e&&e.remove(),b(k())}b(k());re();
|
||||
1
sdwan/dist/assets/index-wI-vnel9.css
vendored
Normal file
1
sdwan/dist/assets/index-wI-vnel9.css
vendored
Normal file
File diff suppressed because one or more lines are too long
9
sdwan/dist/favicon.svg
vendored
Normal file
9
sdwan/dist/favicon.svg
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32">
|
||||
<rect width="32" height="32" rx="6" fill="#0f172a"/>
|
||||
<path d="M6 12 L16 6 L26 12 L26 20 L16 26 L6 20 Z" fill="none" stroke="#38bdf8" stroke-width="2"/>
|
||||
<circle cx="16" cy="16" r="3" fill="#38bdf8"/>
|
||||
<line x1="6" y1="12" x2="16" y2="16" stroke="#38bdf8" stroke-width="1.5" opacity="0.5"/>
|
||||
<line x1="26" y1="12" x2="16" y2="16" stroke="#38bdf8" stroke-width="1.5" opacity="0.5"/>
|
||||
<line x1="6" y1="20" x2="16" y2="16" stroke="#38bdf8" stroke-width="1.5" opacity="0.5"/>
|
||||
<line x1="26" y1="20" x2="16" y2="16" stroke="#38bdf8" stroke-width="1.5" opacity="0.5"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 639 B |
20
sdwan/dist/index.html
vendored
Normal file
20
sdwan/dist/index.html
vendored
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
<!doctype html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>HPE Aruba SD-WAN Traffic Master</title>
|
||||
<script type="module" crossorigin src="/sdwan/assets/index-d6HUX9kC.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/sdwan/assets/index-wI-vnel9.css">
|
||||
</head>
|
||||
<body>
|
||||
<div style="background:#f0f4f8; border-bottom:1px solid #e2e8f0; padding:6px 16px; font-size:13px;">
|
||||
<a href="/" style="color:#64748b; text-decoration:none; display:inline-flex; align-items:center; gap:4px;">
|
||||
← GITEX 2026 Hub
|
||||
</a>
|
||||
</div>
|
||||
<div id="app">
|
||||
<!-- Populated by main.js -->
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Reference in a new issue