ACIL FM
Dark
Refresh
Current DIR:
/home/benbot/public_html/monitor
/
home
benbot
public_html
monitor
Upload
Zip Selected
Delete Selected
Pilih semua
Nama
Ukuran
Permission
Aksi
css
-
chmod
Open
Rename
Delete
.htaccess
647 B
chmod
View
DL
Edit
Rename
Delete
breadth.html
13 MB
chmod
View
DL
Edit
Rename
Delete
eslint.config.mjs
803 B
chmod
View
DL
Edit
Rename
Delete
guide_1.html
18.76 MB
chmod
View
DL
Edit
Rename
Delete
guide_market.html
18.76 MB
chmod
View
DL
Edit
Rename
Delete
guide_ranktop5.html
29.76 MB
chmod
View
DL
Edit
Rename
Delete
index.html
31.38 MB
chmod
View
DL
Edit
Rename
Delete
ls-bias.html
18.24 MB
chmod
View
DL
Edit
Rename
Delete
opsdeck-basic.html
7.11 MB
chmod
View
DL
Edit
Rename
Delete
opsdeck.html
4.96 MB
chmod
View
DL
Edit
Rename
Delete
rank_top5.html
24.79 MB
chmod
View
DL
Edit
Rename
Delete
risk.html
13.32 MB
chmod
View
DL
Edit
Rename
Delete
trade.html
13.87 MB
chmod
View
DL
Edit
Rename
Delete
Edit file: /home/benbot/public_html/monitor/guide_ranktop5.html
<!doctype html> <html lang="ko"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width,initial-scale=1" /> <title>TRADING GUIDE — Bitget USDT-Futures Rank TOP5</title> <style> :root { --bg: #0b0f14; --panel: #0f141a; --card: #0b1117; --line: #1e2a36; --ink: #e6edf3; --muted: #9fb0c3; --pos: #19c37d; --neg: #ef4444; --pill: #1a2230; } * { box-sizing: border-box; } html, body { height: 100%; } body { margin: 0; background: var(--bg); color: var(--ink); font: 14px/1.4 system-ui, -apple-system, Segoe UI, Roboto, "Apple SD Gothic Neo", "Malgun Gothic", sans-serif; display: flex; justify-content: center; align-items: center; overflow: hidden; /* 전체 스크롤 없음 */ } /* ===== 9:16 프레임 ===== */ .viewport-9-16 { height: 100vh; width: calc(100vh * 9 / 16); max-height: 100vh; max-width: 100vw; display: flex; justify-content: center; align-items: flex-start; background: transparent; overflow: hidden; } @media (max-aspect-ratio: 9/16) { .viewport-9-16 { width: 100vw; height: calc(100vw * 16 / 9); } } /* ===== 앱 전체 ===== */ .app-shell { width: 100%; height: 100%; background: var(--bg); padding: 8px 10px 6px; display: flex; flex-direction: column; gap: 6px; } /* ===== 상단 바 ===== */ .brand-bar { display: flex; justify-content: space-between; align-items: center; background: rgba(15, 20, 27, 0.75); border: 1px solid rgba(30, 42, 54, 0.35); border-radius: 12px; padding: 6px 10px 6px; flex: 0 0 auto; } .brand-title { font-weight: 800; font-size: 18px; letter-spacing: 0.02em; } .tz-box { display: flex; gap: 4px; align-items: center; background: rgba(11, 15, 20, 0.1); border: 1px solid rgba(158, 176, 195, 0.15); border-radius: 999px; padding: 2px 9px 2px; } .tz-label { font-size: 11.5px; color: var(--muted); } .tz-time { font-size: 11.5px; font-weight: 600; } /* ===== 본문 ===== */ .main-body { flex: 1 1 auto; display: flex; flex-direction: column; gap: 6px; min-height: 0; } .heading { display: flex; justify-content: space-between; align-items: center; } .heading h1 { font-size: 15px; margin: 0; } .muted { color: var(--muted); font-size: 11.5px; } .panel { background: var(--panel); border: 1px solid var(--line); border-radius: 10px; padding: 6px 8px 4px; display: flex; flex-direction: column; gap: 5px; flex: 1 1 auto; min-height: 0; } .ctrl-row { display: flex; gap: 5px; align-items: center; flex-wrap: wrap; } select, button { background: var(--card); color: var(--ink); border: 1px solid var(--line); border-radius: 7px; padding: 2px 6px 2px; font-size: 12.5px; outline: none; } button { cursor: pointer; } button:hover { border-color: #2b3a4a; } .badge { display: inline-flex; gap: 4px; align-items: center; background: rgba(26, 34, 48, 0.45); border: 1px solid rgba(30, 42, 54, 0.7); border-radius: 999px; padding: 1px 6px 1px; font-size: 10.5px; color: var(--muted); } /* ===== 랭킹 ===== */ .rank-columns { display: flex; flex-direction: column; gap: 4px; flex: 0 0 auto; } .rank-block { background: rgba(11, 15, 20, 0.25); border: 1px solid rgba(30, 42, 54, 0.3); border-radius: 8px; } .rank-title { display: flex; justify-content: space-between; align-items: center; padding: 3px 6px 2px; border-bottom: 1px solid rgba(30, 42, 54, 0.25); } .rank-title h2 { font-size: 12.5px; margin: 0; } table { border-collapse: separate; border-spacing: 0; width: 100%; } thead th { background: #0e141b; border-bottom: 1px solid var(--line); font-weight: 600; text-align: left; font-size: 11px; } th, td { padding: 3px 5px; border-bottom: 1px solid rgba(30, 42, 54, 0.18); white-space: nowrap; font-size: 11.5px; } tr:last-child td { border-bottom: none; } tr.clickable { cursor: pointer; } tr.clickable:hover { background: rgba(25, 195, 125, 0.07); } tr.active-row { background: rgba(25, 195, 125, 0.12); } td.left, th.left { text-align: left; } td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; } .pos { color: var(--pos); } .neg { color: var(--neg); } /* ===== 상세 패널 (tight v2) ===== */ .detail-panel { background: rgba(11, 15, 20, 0.28); border: 1px solid rgba(30, 42, 54, 0.55); border-radius: 8px; padding: 4px 6px 3px; /* 한 단계 더 줄임 */ display: flex; flex-direction: column; gap: 3px; flex: 0 0 auto; } .detail-header { display: flex; justify-content: space-between; align-items: center; } .detail-title { font-weight: 700; font-size: 13.5px; } .detail-symbol { font-size: 13.5px; font-weight: 700; } .detail-grid { display: grid; grid-template-columns: repeat(3, minmax(90px, 1fr)); gap: 2px; /* 3px → 2px */ } @media (max-width: 600px) { .detail-grid { grid-template-columns: repeat(2, minmax(90px, 1fr)); } } .detail-item { background: rgba(15, 20, 27, 0.4); border: 1px solid rgba(30, 42, 54, 0.35); border-radius: 6px; padding: 1px 5px 2px; /* ← 핵심: 위 1px / 아래 2px */ } .detail-label { font-size: 12px; color: var(--muted); margin-bottom: 0; /* 1px → 0 */ } .detail-value { font-size: 13.3px; font-weight: 600; line-height: 1.1; /* 1.2 → 1.1 */ color: #fff; } .section-title { grid-column: 1 / -1; font-size: 12px; font-weight: 600; color: var(--muted); margin-top: 0; margin-bottom: 0; /* 1px → 0 */ } </style> </head> <body> <div class="viewport-9-16"> <div class="app-shell" id="appShell"> <div class="brand-bar"> <div class="brand-title">TRADING GUIDE</div> <div class="tz-box"> <span class="tz-label">LA (PDT)</span> <span class="tz-time" id="laTime">LA (PDT) · --:--:--</span> </div> </div> <div class="main-body"> <div class="heading"> <h1>Bitget USDT-Futures Rank TOP5</h1> <span id="status" class="muted">대기</span> </div> <div class="panel"> <div class="ctrl-row"> <label for="period" class="muted">주기:</label> <select id="period"> <option value="2000">2s</option> <option value="5000" selected>5s</option> <option value="10000">10s</option> <option value="30000">30s</option> </select> <button id="btnStart">Start</button> <button id="btnStop">Stop</button> <span class="badge">캔들 60s</span> </div> <div class="rank-columns"> <div class="rank-block" id="longBlock"> <div class="rank-title"> <h2>상승(선물 기준)</h2> <span class="muted">Long TOP 5</span> </div> <table id="tblLong"> <thead> <tr> <th class="left">순위</th> <th class="left">심볼</th> <th class="num">Fut%</th> <th class="num">Spot%</th> <th class="num">가격</th> </tr> </thead> <tbody></tbody> </table> </div> <div class="rank-block" id="shortBlock"> <div class="rank-title"> <h2>하락(선물 기준)</h2> <span class="muted">Short TOP 5</span> </div> <table id="tblShort"> <thead> <tr> <th class="left">순위</th> <th class="left">심볼</th> <th class="num">Fut%</th> <th class="num">Spot%</th> <th class="num">가격</th> </tr> </thead> <tbody></tbody> </table> </div> </div> <!-- ===== 상세 정보 (tight v2) ===== --> <div class="detail-panel" id="detailPanel"> <div class="detail-header"> <div class="detail-title">상세 정보</div> <div class="detail-symbol" id="detailSymbol">행을 클릭하세요</div> </div> <div class="detail-grid" id="detailGrid"> <!-- 기본 시세 --> <div class="section-title">기본 시세</div> <div class="detail-item"> <div class="detail-label">가격(USDT)</div> <div class="detail-value" id="detailPrice">-</div> </div> <div class="detail-item"> <div class="detail-label">Fut%</div> <div class="detail-value" id="detailFut">-</div> </div> <div class="detail-item"> <div class="detail-label">Spot%</div> <div class="detail-value" id="detailSpot">-</div> </div> <div class="detail-item"> <div class="detail-label">거래량(USDT)</div> <div class="detail-value" id="detailVol">-</div> </div> <div class="detail-item"> <div class="detail-label">24h 고가</div> <div class="detail-value" id="detailHigh">-</div> </div> <div class="detail-item"> <div class="detail-label">24h 고가 시각</div> <div class="detail-value" id="detailHighT">-</div> </div> <div class="detail-item"> <div class="detail-label">24h 저가</div> <div class="detail-value" id="detailLow">-</div> </div> <div class="detail-item"> <div class="detail-label">24h 저가 시각</div> <div class="detail-value" id="detailLowT">-</div> </div> <!-- 비교 지표 --> <div class="section-title">비교 지표</div> <div class="detail-item"> <div class="detail-label">TOP5 거래량 비중</div> <div class="detail-value" id="detailVolShare">-</div> </div> <div class="detail-item"> <div class="detail-label">24h 변동폭</div> <div class="detail-value" id="detailVolatility">-</div> </div> <div class="detail-item"> <div class="detail-label">선물-현물 프리미엄</div> <div class="detail-value" id="detailPremium">-</div> </div> <!-- 포지션 / 선물 --> <div class="section-title">포지션 / 선물</div> <div class="detail-item"> <div class="detail-label">펀딩비</div> <div class="detail-value" id="detailFunding">조회중…</div> </div> <div class="detail-item"> <div class="detail-label">미결제약정(OI)</div> <div class="detail-value" id="detailOI">조회중…</div> </div> <div class="detail-item"> <div class="detail-label">롱/숏 비율</div> <div class="detail-value" id="detailLS">조회중…</div> </div> </div> </div> <!-- ===== 상세 정보 끝 ===== --> </div> </div> </div> </div> <script> const API = "https://api.bitget.com"; const PRODUCT_TYPE = "USDT-FUTURES"; const MIX_SUFFIXES = ["_UMCBL", "_DMCBL", "_CMCBL"]; const EXCLUDE_BASES = ["USDT", "USDC", "BGB", "WBTC", "STETH"]; let lastTopRows = []; let lastTopTotalVolume = 0; let lastSpotMap = new Map(); const num = (v) => { const n = Number(v); return Number.isFinite(n) ? n : NaN; }; const pctFmt = (v, d = 2) => Number.isFinite(v) ? v.toFixed(d) + "%" : "-"; const nfix = (v, p = 6) => (Number.isFinite(v) ? v.toFixed(p) : ""); const nint = (v) => Number.isFinite(v) ? v.toLocaleString("en-US", { maximumFractionDigits: 0 }) : ""; const clsPct = (v) => (v > 0 ? "pos" : v < 0 ? "neg" : ""); function normalizeSymbol(sym) { const up = String(sym || "").toUpperCase(); for (const suf of MIX_SUFFIXES) { if (up.endsWith(suf)) return up.slice(0, -suf.length); } return up; } function filterUsdt(sym) { const core = normalizeSymbol(sym); const base = core.replace(/USDT.*/, ""); if (EXCLUDE_BASES.includes(base)) return false; return /USDT$/i.test(core); } /* ===== LA(PDT) ===== */ function updateLATime() { const el = document.getElementById("laTime"); if (!el) return; const now = new Date(); const la = now.toLocaleTimeString("en-US", { timeZone: "America/Los_Angeles", hour12: false, }); el.textContent = "LA (PDT) · " + la; } setInterval(updateLATime, 1000); updateLATime(); /* ===== 데이터 ===== */ const N = 5; const CANDLE_REFRESH_MS = 60000; const GRANULARITY = "5m"; const LOOKBACK_BARS = 288; let rankTimer = null; let candleTimer = null; const candleCache = new Map(); async function fetchJSON(url, opt) { const r = await fetch(url, opt); if (!r.ok) throw new Error("HTTP " + r.status); return r.json(); } function calcPctFromTicker(t, isSpot = false) { const last = num(t.lastPr ?? t.last ?? t.close ?? t.lastPrice); const open = num(t.open24h ?? t.openPr ?? t.open ?? t.openPrice); if (Number.isFinite(last) && Number.isFinite(open) && open !== 0) { return ((last - open) / open) * 100; } let raw = num( isSpot ? (t.change ?? t.change24h) : (t.change24h ?? t.change), ); if (Number.isFinite(raw)) { if (Math.abs(raw) < 1) raw *= 100; return raw; } return NaN; } async function fetchFuturesTickers() { const j = await fetchJSON( `${API}/api/v2/mix/market/tickers?productType=${encodeURIComponent(PRODUCT_TYPE)}`, ); const arr = Array.isArray(j?.data) ? j.data : []; const out = []; for (const t of arr) { const raw = String(t.symbol || ""); const core = normalizeSymbol(raw); if (!filterUsdt(core)) continue; out.push({ symbol: core, rawSymbol: raw, last: num(t.lastPr ?? t.last ?? t.close ?? t.lastPrice), futPct: calcPctFromTicker(t, false), volUSDT: num(t.usdtVolume ?? t.quoteVolume), open24h: num(t.open24h), }); } return out; } async function fetchSpotTickersMap() { const j = await fetchJSON(`${API}/api/v2/spot/market/tickers`); const arr = Array.isArray(j?.data) ? j.data : []; const map = new Map(); for (const t of arr) { const raw = String(t.symbol || t.instId || "").toUpperCase(); const core = normalizeSymbol(raw); const sp = calcPctFromTicker(t, true); if (filterUsdt(core)) { const spotLast = num( t.lastPr ?? t.last ?? t.close ?? t.lastPrice ?? t.buyOne, ); map.set(core, { pct: sp, price: spotLast }); } } return map; } async function fetchCandles(symbol, endTimeMs = null, limit = 200) { const params = new URLSearchParams({ symbol, granularity: GRANULARITY, productType: PRODUCT_TYPE, limit: String(limit), }); if (endTimeMs) params.set("endTime", String(endTimeMs)); const j = await fetchJSON( `${API}/api/v2/mix/market/history-candles?${params.toString()}`, ); return Array.isArray(j?.data) ? j.data : []; } async function ensureCandleInfo(symbol) { const cache = candleCache.get(symbol); if (cache && Date.now() - cache.asOf < CANDLE_REFRESH_MS) return cache; try { let bars = await fetchCandles(symbol, null, 200); if (bars.length < LOOKBACK_BARS) { const oldest = bars.length ? Number(bars[bars.length - 1][0]) : null; if (oldest) { const more = await fetchCandles(symbol, oldest - 1, 200); bars = bars.concat(more); } } bars.sort((a, b) => Number(a[0]) - Number(b[0])); if (bars.length > LOOKBACK_BARS) bars = bars.slice(-LOOKBACK_BARS); let hi = -Infinity, hiT = null, lo = Infinity, loT = null; for (const k of bars) { const ts = +k[0]; const h = num(k[2]); const l = num(k[3]); if (h > hi) { hi = h; hiT = ts; } if (l < lo) { lo = l; loT = ts; } } const info = { high: hi, highT: hiT, low: lo, lowT: loT, asOf: Date.now(), }; candleCache.set(symbol, info); return info; } catch { return { high: NaN, highT: null, low: NaN, lowT: null, asOf: Date.now(), }; } } async function fetchFunding(rawSymbol) { try { const j = await fetchJSON( `${API}/api/v2/mix/market/current-fundRate?symbol=${encodeURIComponent(rawSymbol)}`, ); const rate = num(j?.data?.fundingRate); return Number.isFinite(rate) ? rate * 100 : NaN; } catch { return NaN; } } async function fetchOpenInterest(rawSymbol) { try { const j = await fetchJSON( `${API}/api/v2/mix/market/open-interest?symbol=${encodeURIComponent(rawSymbol)}&productType=${encodeURIComponent(PRODUCT_TYPE)}`, ); const oi = num(j?.data?.openInterest ?? j?.data?.size); return Number.isFinite(oi) ? oi : NaN; } catch { return NaN; } } async function fetchLongShort(rawSymbol) { try { const j = await fetchJSON( `${API}/api/v2/mix/market/accountLongShortRatio?symbol=${encodeURIComponent(rawSymbol)}&period=5m`, ); const arr = Array.isArray(j?.data) ? j.data : []; const last = arr.length ? arr[arr.length - 1] : null; if (!last) return { long: NaN, short: NaN }; return { long: num(last.longAccount), short: num(last.shortAccount), }; } catch { return { long: NaN, short: NaN }; } } async function renderDetail(row) { if (!row) return; document.getElementById("detailSymbol").textContent = row.data.symbol; document.getElementById("detailPrice").textContent = nfix( row.data.last, 6, ); document.getElementById("detailFut").textContent = pctFmt( row.data.futPct, ); document.getElementById("detailSpot").textContent = Number.isFinite( row.data.spotPct, ) ? pctFmt(row.data.spotPct) : "-"; document.getElementById("detailVol").textContent = nint( row.data.volUSDT, ); document.getElementById("detailHigh").textContent = nfix(row.high, 6); document.getElementById("detailHighT").textContent = row.highT ? new Date(row.highT).toLocaleString() : "-"; document.getElementById("detailLow").textContent = nfix(row.low, 6); document.getElementById("detailLowT").textContent = row.lowT ? new Date(row.lowT).toLocaleString() : "-"; if (lastTopTotalVolume > 0 && Number.isFinite(row.data.volUSDT)) { const share = (row.data.volUSDT / lastTopTotalVolume) * 100; document.getElementById("detailVolShare").textContent = share.toFixed(1) + " %"; } else { document.getElementById("detailVolShare").textContent = "-"; } if (Number.isFinite(row.high) && Number.isFinite(row.low) && row.low > 0) { const volPct = ((row.high - row.low) / row.low) * 100; document.getElementById("detailVolatility").textContent = volPct.toFixed(2) + " %"; } else { document.getElementById("detailVolatility").textContent = "-"; } const spotInfo = lastSpotMap.get(row.data.symbol); if ( spotInfo && Number.isFinite(spotInfo.price) && Number.isFinite(row.data.last) && spotInfo.price !== 0 ) { const prem = ((row.data.last - spotInfo.price) / spotInfo.price) * 100; document.getElementById("detailPremium").textContent = prem.toFixed(2) + " %"; } else { document.getElementById("detailPremium").textContent = "-"; } document.getElementById("detailFunding").textContent = "조회중…"; document.getElementById("detailOI").textContent = "조회중…"; document.getElementById("detailLS").textContent = "조회중…"; const symForApi = row.data.rawSymbol || row.data.symbol; const [funding, oi, ls] = await Promise.all([ fetchFunding(symForApi), fetchOpenInterest(symForApi), fetchLongShort(symForApi), ]); document.getElementById("detailFunding").textContent = Number.isFinite( funding, ) ? funding.toFixed(4) + " %" : "-"; document.getElementById("detailOI").textContent = Number.isFinite(oi) ? nint(oi) : "-"; if (Number.isFinite(ls.long) && Number.isFinite(ls.short)) { document.getElementById("detailLS").textContent = ls.long.toFixed(1) + " / " + ls.short.toFixed(1); } else { document.getElementById("detailLS").textContent = "-"; } } function clearActiveRows() { document .querySelectorAll("tr.active-row") .forEach((tr) => tr.classList.remove("active-row")); } function renderTables(gainers, losers) { const longBody = document.querySelector("#tblLong tbody"); const shortBody = document.querySelector("#tblShort tbody"); longBody.innerHTML = ""; shortBody.innerHTML = ""; for (const e of gainers) { const d = e.data; const tr = document.createElement("tr"); tr.className = "clickable"; tr.innerHTML = ` <td class="left">${e.rank}</td> <td class="left">${d.symbol}</td> <td class="num ${clsPct(d.futPct)}">${pctFmt(d.futPct)}</td> <td class="num ${clsPct(d.spotPct)}">${ Number.isFinite(d.spotPct) ? pctFmt(d.spotPct) : "-" }</td> <td class="num">${nfix(d.last, 6)}</td> `; tr.addEventListener("click", () => { clearActiveRows(); tr.classList.add("active-row"); renderDetail(e); }); longBody.appendChild(tr); } for (const e of losers) { const d = e.data; const tr = document.createElement("tr"); tr.className = "clickable"; tr.innerHTML = ` <td class="left">${e.rank}</td> <td class="left">${d.symbol}</td> <td class="num ${clsPct(d.futPct)}">${pctFmt(d.futPct)}</td> <td class="num ${clsPct(d.spotPct)}">${ Number.isFinite(d.spotPct) ? pctFmt(d.spotPct) : "-" }</td> <td class="num">${nfix(d.last, 6)}</td> `; tr.addEventListener("click", () => { clearActiveRows(); tr.classList.add("active-row"); renderDetail(e); }); shortBody.appendChild(tr); } } async function refreshRank() { const st = document.getElementById("status"); try { st.textContent = "요청 중…"; const [futs, spotMap] = await Promise.all([ fetchFuturesTickers(), fetchSpotTickersMap(), ]); lastSpotMap = new Map(); for (const [k, v] of spotMap.entries()) lastSpotMap.set(k, v); const rows = futs .filter((r) => Number.isFinite(r.futPct)) .map((r) => ({ ...r, spotPct: spotMap.get(r.symbol)?.pct ?? NaN, })); const desc = [...rows].sort((a, b) => b.futPct - a.futPct); const asc = [...rows].sort((a, b) => a.futPct - b.futPct); const gainers = desc .slice(0, N) .map((d, i) => ({ rank: i + 1, side: "+", data: d })); const losers = asc .slice(0, N) .map((d, i) => ({ rank: i + 1, side: "-", data: d })); const targets = [...gainers, ...losers]; await Promise.all( targets.map(async (e) => { const symForCandle = e.data.rawSymbol || e.data.symbol; const info = await ensureCandleInfo(symForCandle); e.high = info.high; e.highT = info.highT; e.low = info.low; e.lowT = info.lowT; }), ); lastTopRows = targets; lastTopTotalVolume = targets.reduce((sum, e) => { return sum + (Number.isFinite(e.data.volUSDT) ? e.data.volUSDT : 0); }, 0); renderTables(gainers, losers); const first = document.querySelector("#tblLong tbody tr"); if (first && gainers.length) { first.classList.add("active-row"); renderDetail(gainers[0]); } else if (losers.length) { const sfirst = document.querySelector("#tblShort tbody tr"); if (sfirst) sfirst.classList.add("active-row"); renderDetail(losers[0]); } st.textContent = "업데이트: " + new Date().toLocaleTimeString(); } catch (err) { console.error(err); st.textContent = "에러: " + err.message; } } function start() { stop(); const ms = Number(document.getElementById("period").value || 5000); refreshRank(); rankTimer = setInterval(refreshRank, ms); candleTimer = setInterval(() => { candleCache.clear(); if (lastTopRows.length) refreshRank(); }, CANDLE_REFRESH_MS); } function stop() { if (rankTimer) { clearInterval(rankTimer); rankTimer = null; } if (candleTimer) { clearInterval(candleTimer); candleTimer = null; } document.getElementById("status").textContent = "정지"; } document.getElementById("btnStart").addEventListener("click", start); document.getElementById("btnStop").addEventListener("click", stop); window.addEventListener("load", () => { start(); }); </script> </body> </html>
Simpan
Batal
Isi Zip:
Unzip
Create
Buat Folder
Buat File
Terminal / Execute
Run
Chmod Bulk
All File
All Folder
All File dan Folder
Apply