{"id":1154,"date":"2026-01-10T23:14:34","date_gmt":"2026-01-10T23:14:34","guid":{"rendered":"https:\/\/southsunindustries.com\/?page_id=1154"},"modified":"2026-01-16T00:57:12","modified_gmt":"2026-01-16T00:57:12","slug":"login-test-page","status":"publish","type":"page","link":"https:\/\/southsunindustries.com\/index.php\/login-test-page\/","title":{"rendered":"Login test page"},"content":{"rendered":"\n<!doctype html>\n<html lang=\"en\">\n<head>\n  <meta charset=\"utf-8\" \/>\n  <meta name=\"viewport\" content=\"width=device-width,initial-scale=1\" \/>\n  <title>EVE Modules: Amarr Buy vs Scrap @ 55%<\/title>\n  <style>\n    :root { color-scheme: dark; }\n    body { margin:0; font-family:system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif; background:#0b0f14; color:#e8eef6; }\n    .wrap { max-width: 1180px; margin: 0 auto; padding: 22px; }\n    .card { background:#111826; border:1px solid #223044; border-radius:14px; padding:18px; box-shadow:0 10px 30px rgba(0,0,0,.35); }\n    h1 { font-size: 18px; margin: 0 0 10px; font-weight: 700; }\n    .muted { color:#a9b7cc; font-size: 13px; line-height: 1.35; margin: 8px 0 0; }\n    .grid { display:grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 12px; }\n    .panel { background:#0c1220; border:1px solid #263552; border-radius:12px; padding: 12px; }\n    .panel h2 { font-size: 13px; margin:0 0 8px; color:#a9b7cc; font-weight:700; letter-spacing:.2px; }\n    textarea, input, button {\n      background:#0b1222; border:1px solid #2a3a55; color:#e8eef6;\n      padding: 10px 12px; border-radius: 10px; font-size: 14px;\n    }\n    textarea { width: 100%; min-height: 170px; resize: vertical; }\n    input { width: 100%; }\n    button { cursor: pointer; font-weight: 700; }\n    button:disabled { opacity: .6; cursor: not-allowed; }\n    .row { display:flex; gap: 10px; flex-wrap: wrap; align-items: center; }\n    .pill { display:inline-block; padding:2px 8px; border-radius:999px; background:#0b1222; border:1px solid #2a3a55; color:#a9b7cc; font-size:12px; }\n    .hr { height:1px; background:#23324a; margin: 16px 0; }\n    .status { margin-top: 10px; font-size: 13px; color:#a9b7cc; }\n    .status.error { color:#ffb4b4; }\n    .status.ok { color:#b7ffcf; }\n    table { width:100%; border-collapse: collapse; font-size: 13px; }\n    th, td { padding: 10px 8px; border-bottom: 1px solid #223044; text-align: left; vertical-align: top; }\n    th { color:#a9b7cc; font-weight: 700; }\n    .right { text-align: right; }\n    .tiny { font-size: 12px; color:#a9b7cc; }\n    @media (max-width: 980px){ .grid { grid-template-columns: 1fr; } }\n  <\/style>\n<\/head>\n<body>\n<div class=\"wrap\">\n  <div class=\"card\">\n    <h1>Modules Calculator: Amarr Buy vs Scrap Value @ 55% Reprocessing<\/h1>\n    <div class=\"muted\">\n      Single-file, offline tool. You paste inventory + Amarr buy prices + scrap outputs. Then it compares them side-by-side.\n      Efficiency is fixed at <span class=\"pill\">55%<\/span>.\n    <\/div>\n\n    <div class=\"hr\"><\/div>\n\n    <div class=\"grid\">\n      <div class=\"panel\">\n        <h2>1) Inventory (paste)<\/h2>\n        <div class=\"muted\" style=\"margin-top:0\">\n          One line per item. Examples:\n          <span class=\"pill\">Warp Disruptor II x2<\/span>\n          <span class=\"pill\">Damage Control II 5<\/span>\n          <span class=\"pill\">50MN Microwarpdrive II, 1<\/span>\n          <span class=\"pill\">Multispectrum Shield Hardener II\\t3<\/span>\n        <\/div>\n        <textarea id=\"inv\" placeholder=\"Paste your module inventory here...\"><\/textarea>\n      <\/div>\n\n      <div class=\"panel\">\n        <h2>2) Mineral prices (Amarr buy, per unit)<\/h2>\n        <div class=\"muted\" style=\"margin-top:0\">\n          Used to value scrap outputs. Format: <span class=\"pill\">Mineral<TAB>Price<\/span>\n        <\/div>\n        <textarea id=\"minPrices\" spellcheck=\"false\">Tritanium\t0\nPyerite\t0\nMexallon\t0\nIsogen\t0\nNocxium\t0\nZydrine\t0\nMegacyte\t0\nMorphite\t0<\/textarea>\n      <\/div>\n\n      <div class=\"panel\">\n        <h2>3) Item prices (Amarr buy, per item)<\/h2>\n        <div class=\"muted\" style=\"margin-top:0\">\n          Format: <span class=\"pill\">Item Name<TAB>Price<\/span> (one per line).\n        <\/div>\n        <textarea id=\"itemPrices\" spellcheck=\"false\" placeholder=\"Example:\nDamage Control II\t325000\nWarp Disruptor II\t980000\"><\/textarea>\n      <\/div>\n\n      <div class=\"panel\">\n        <h2>4) Scrap outputs (per 1 item at 100% yield)<\/h2>\n        <div class=\"muted\" style=\"margin-top:0\">\n          Format per line:\n          <span class=\"pill\">Item Name<TAB>Mineral1=Qty;Mineral2=Qty;&#8230;<\/span><br>\n          Example:\n          <span class=\"pill\">Damage Control II<TAB>Tritanium=1200;Pyerite=340;Mexallon=55<\/span>\n        <\/div>\n        <textarea id=\"scrapMap\" spellcheck=\"false\" placeholder=\"Example:\nDamage Control II\tTritanium=1200;Pyerite=340;Mexallon=55\nWarp Disruptor II\tTritanium=900;Pyerite=210;Mexallon=40\"><\/textarea>\n      <\/div>\n    <\/div>\n\n    <div class=\"hr\"><\/div>\n\n    <div class=\"row\">\n      <button id=\"run\">Compare<\/button>\n      <button id=\"copy\">Copy results (TSV)<\/button>\n      <button id=\"clear\">Clear results<\/button>\n      <div class=\"pill\">Scrap efficiency: <span id=\"eff\">55%<\/span><\/div>\n      <div id=\"status\" class=\"status\"><\/div>\n    <\/div>\n\n    <div class=\"hr\"><\/div>\n\n    <div class=\"row\" style=\"justify-content:space-between; align-items:center;\">\n      <div class=\"muted\" style=\"margin:0;\">\n        Totals:\n        <span class=\"pill\" id=\"totBuy\">Buy: \u2014<\/span>\n        <span class=\"pill\" id=\"totScrap\">Scrap: \u2014<\/span>\n        <span class=\"pill\" id=\"totDiff\">Diff: \u2014<\/span>\n      <\/div>\n      <div class=\"tiny\">Diff = Scrap \u2212 Buy<\/div>\n    <\/div>\n\n    <div style=\"overflow:auto; margin-top:10px;\">\n      <table>\n        <thead>\n          <tr>\n            <th style=\"min-width:260px;\">Item<\/th>\n            <th class=\"right\">Qty<\/th>\n            <th class=\"right\">Amarr buy (each)<\/th>\n            <th class=\"right\">Amarr buy (total)<\/th>\n            <th class=\"right\">Scrap @55% (each)<\/th>\n            <th class=\"right\">Scrap @55% (total)<\/th>\n            <th class=\"right\">Diff<\/th>\n            <th class=\"tiny\">Notes<\/th>\n          <\/tr>\n        <\/thead>\n        <tbody id=\"rows\">\n          <tr><td colspan=\"8\" class=\"muted\">No results yet.<\/td><\/tr>\n        <\/tbody>\n      <\/table>\n    <\/div>\n\n    <div class=\"muted\" style=\"margin-top:12px;\">\n      Tip: set mineral prices to Amarr buy. Then scrap value is just the minerals \u00d7 prices \u00d7 0.55.\n    <\/div>\n  <\/div>\n<\/div>\n\n<script>\n(() => {\n  const EFF = 0.55;\n\n  const $ = (id) => document.getElementById(id);\n  $(\"eff\").textContent = (EFF * 100).toFixed(0) + \"%\";\n\n  function setStatus(msg, kind=\"muted\") {\n    const el = $(\"status\");\n    el.className = \"status\" + (kind === \"error\" ? \" error\" : (kind === \"ok\" ? \" ok\" : \"\"));\n    el.textContent = msg;\n  }\n\n  function fmtIsk(n) {\n    if (n == null || !Number.isFinite(n)) return \"\u2014\";\n    return n.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 }) + \" ISK\";\n  }\n\n  function fmtNum(n) {\n    if (n == null || !Number.isFinite(n)) return \"\u2014\";\n    return n.toLocaleString(undefined, { maximumFractionDigits: 2 });\n  }\n\n  function esc(s) {\n    return String(s).replace(\/[&<>\"']\/g, c => ({\n      \"&\":\"&amp;\",\"<\":\"&lt;\",\">\":\"&gt;\",'\"':\"&quot;\",\"'\":\"&#39;\"\n    }[c]));\n  }\n\n  \/\/ Accept:\n  \/\/ \"Item x2\", \"Item 2\", \"Item,2\", \"Item\\t2\"\n  function parseInventory(text) {\n    const lines = text.split(\/\\r?\\n\/).map(l => l.trim()).filter(Boolean);\n    const out = [];\n    for (const line of lines) {\n      let name = line;\n      let qty = 1;\n\n      const tab = line.split(\/\\t+\/);\n      if (tab.length >= 2) {\n        name = tab[0].trim();\n        qty = Number(tab[1].trim().replace(\/,\/g,\"\"));\n      } else {\n        const comma = line.split(\/\\s*,\\s*\/);\n        if (comma.length >= 2 && \/^\\d+(\\.\\d+)?$\/.test(comma[comma.length-1])) {\n          name = comma.slice(0, -1).join(\",\").trim();\n          qty = Number(comma[comma.length-1]);\n        } else {\n          const m = line.match(\/^(.*?)(?:\\s*[x\u00d7]\\s*|\\s+)(\\d+(?:\\.\\d+)?)\\s*$\/i);\n          if (m) {\n            name = m[1].trim();\n            qty = Number(m[2]);\n          }\n        }\n      }\n\n      if (!name) continue;\n      if (!Number.isFinite(qty) || qty <= 0) qty = 1;\n      out.push({ name, qty });\n    }\n    return out;\n  }\n\n  \/\/ Generic TAB parser: \"Key<TAB>Value\"\n  function parseTabMap(text) {\n    const map = new Map();\n    const lines = text.split(\/\\r?\\n\/).map(l => l.trim()).filter(Boolean);\n    for (const line of lines) {\n      const parts = line.split(\/\\t+\/);\n      if (parts.length < 2) continue;\n      const key = parts[0].trim();\n      const val = Number(parts.slice(1).join(\"\\t\").trim().replace(\/,\/g,\"\"));\n      if (!key) continue;\n      if (!Number.isFinite(val)) continue;\n      map.set(key, val);\n    }\n    return map;\n  }\n\n  \/\/ Scrap format:\n  \/\/ Item<TAB>Mineral=Qty;Mineral=Qty\n  function parseScrapMap(text) {\n    const map = new Map(); \/\/ item -> [{mineral, qty}]\n    const lines = text.split(\/\\r?\\n\/).map(l => l.trim()).filter(Boolean);\n    for (const line of lines) {\n      const parts = line.split(\/\\t+\/);\n      if (parts.length < 2) continue;\n      const item = parts[0].trim();\n      const rhs = parts.slice(1).join(\"\\t\").trim();\n      if (!item || !rhs) continue;\n\n      const entries = rhs.split(\/\\s*;\\s*\/).filter(Boolean).map(seg => {\n        const m = seg.split(\/\\s*=\\s*\/);\n        if (m.length < 2) return null;\n        const mineral = m[0].trim();\n        const qty = Number(m.slice(1).join(\"=\").trim().replace(\/,\/g,\"\"));\n        if (!mineral || !Number.isFinite(qty)) return null;\n        return { mineral, qty };\n      }).filter(Boolean);\n\n      if (entries.length) map.set(item, entries);\n    }\n    return map;\n  }\n\n  function calcScrapEach(itemName, scrapMap, mineralPrices) {\n    const mats = scrapMap.get(itemName);\n    if (!mats) return { value: null, note: \"No scrap data for item\" };\n\n    let total = 0;\n    let priced = 0;\n    let missing = [];\n    for (const { mineral, qty } of mats) {\n      const p = mineralPrices.get(mineral);\n      if (p == null) { missing.push(mineral); continue; }\n      total += qty * p;\n      priced++;\n    }\n    if (priced === 0) return { value: null, note: \"No mineral prices set\" };\n\n    const v = total * EFF;\n    const note = missing.length ? `Missing mineral prices: ${missing.join(\", \")}` : \"\";\n    return { value: v, note };\n  }\n\n  function render(results) {\n    const tbody = $(\"rows\");\n    if (!results.length) {\n      tbody.innerHTML = `<tr><td colspan=\"8\" class=\"muted\">No results.<\/td><\/tr>`;\n      return;\n    }\n\n    tbody.innerHTML = results.map(r => {\n      const diff = (r.scrapTotal != null && r.buyTotal != null) ? (r.scrapTotal - r.buyTotal) : null;\n      return `\n        <tr>\n          <td>${esc(r.name)}<\/td>\n          <td class=\"right\">${fmtNum(r.qty)}<\/td>\n          <td class=\"right\">${r.buyEach == null ? \"N\/A\" : fmtIsk(r.buyEach)}<\/td>\n          <td class=\"right\">${r.buyTotal == null ? \"\u2014\" : fmtIsk(r.buyTotal)}<\/td>\n          <td class=\"right\">${r.scrapEach == null ? \"N\/A\" : fmtIsk(r.scrapEach)}<\/td>\n          <td class=\"right\">${r.scrapTotal == null ? \"\u2014\" : fmtIsk(r.scrapTotal)}<\/td>\n          <td class=\"right\">${diff == null ? \"\u2014\" : fmtIsk(diff)}<\/td>\n          <td class=\"tiny\">${esc(r.note || \"\")}<\/td>\n        <\/tr>\n      `;\n    }).join(\"\");\n  }\n\n  function tsv(results) {\n    const header = [\"Item\",\"Qty\",\"AmarrBuyEach\",\"AmarrBuyTotal\",\"ScrapEach55\",\"ScrapTotal55\",\"Diff\"].join(\"\\t\");\n    const lines = results.map(r => {\n      const diff = (r.scrapTotal != null && r.buyTotal != null) ? (r.scrapTotal - r.buyTotal) : \"\";\n      return [\n        r.name,\n        r.qty,\n        r.buyEach ?? \"\",\n        r.buyTotal ?? \"\",\n        r.scrapEach ?? \"\",\n        r.scrapTotal ?? \"\",\n        diff\n      ].join(\"\\t\");\n    });\n    return [header, ...lines].join(\"\\n\");\n  }\n\n  let lastResults = [];\n\n  $(\"run\").addEventListener(\"click\", () => {\n    setStatus(\"\");\n\n    const inv = parseInventory($(\"inv\").value);\n    if (!inv.length) {\n      setStatus(\"Paste your inventory first.\", \"error\");\n      return;\n    }\n\n    const mineralPrices = parseTabMap($(\"minPrices\").value);\n    const itemPrices = parseTabMap($(\"itemPrices\").value);\n    const scrapMap = parseScrapMap($(\"scrapMap\").value);\n\n    \/\/ calculate\n    const results = inv.map(({name, qty}) => {\n      const buyEach = itemPrices.get(name) ?? null;\n      const buyTotal = (buyEach == null ? null : buyEach * qty);\n\n      const scrap = calcScrapEach(name, scrapMap, mineralPrices);\n      const scrapEach = (scrap.value == null ? null : scrap.value);\n      const scrapTotal = (scrapEach == null ? null : scrapEach * qty);\n\n      let noteParts = [];\n      if (buyEach == null) noteParts.push(\"No Amarr buy price\");\n      if (scrap.note) noteParts.push(scrap.note);\n\n      return {\n        name, qty,\n        buyEach, buyTotal,\n        scrapEach, scrapTotal,\n        note: noteParts.join(\" \u2022 \")\n      };\n    });\n\n    \/\/ totals\n    let totBuy = 0, totScrap = 0;\n    let hasBuy = 0, hasScrap = 0;\n    for (const r of results) {\n      if (r.buyTotal != null && Number.isFinite(r.buyTotal)) { totBuy += r.buyTotal; hasBuy++; }\n      if (r.scrapTotal != null && Number.isFinite(r.scrapTotal)) { totScrap += r.scrapTotal; hasScrap++; }\n    }\n    const diff = (hasBuy && hasScrap) ? (totScrap - totBuy) : null;\n\n    $(\"totBuy\").textContent = \"Buy: \" + (hasBuy ? fmtIsk(totBuy) : \"\u2014\");\n    $(\"totScrap\").textContent = \"Scrap: \" + (hasScrap ? fmtIsk(totScrap) : \"\u2014\");\n    $(\"totDiff\").textContent = \"Diff: \" + (diff == null ? \"\u2014\" : fmtIsk(diff));\n\n    lastResults = results;\n    render(results);\n\n    setStatus(`Done. Lines: ${results.length}. (Missing prices\/data are marked in Notes.)`, \"ok\");\n  });\n\n  $(\"copy\").addEventListener(\"click\", async () => {\n    if (!lastResults.length) { setStatus(\"Nothing to copy yet.\", \"error\"); return; }\n    try {\n      await navigator.clipboard.writeText(tsv(lastResults));\n      setStatus(\"Copied results as TSV.\", \"ok\");\n    } catch {\n      setStatus(\"Clipboard blocked by browser. Select\/copy manually from the table.\", \"error\");\n    }\n  });\n\n  $(\"clear\").addEventListener(\"click\", () => {\n    lastResults = [];\n    $(\"rows\").innerHTML = `<tr><td colspan=\"8\" class=\"muted\">No results yet.<\/td><\/tr>`;\n    $(\"totBuy\").textContent = \"Buy: \u2014\";\n    $(\"totScrap\").textContent = \"Scrap: \u2014\";\n    $(\"totDiff\").textContent = \"Diff: \u2014\";\n    setStatus(\"\");\n  });\n})();\n<\/script>\n<\/body>\n<\/html>\n\n","protected":false},"excerpt":{"rendered":"<p> [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"_price":"","_stock":"","_tribe_ticket_header":"","_tribe_default_ticket_provider":"","_ticket_start_date":"","_ticket_end_date":"","_tribe_ticket_show_description":"","_tribe_ticket_show_not_going":false,"_tribe_ticket_use_global_stock":"","_tribe_ticket_global_stock_level":"","_global_stock_mode":"","_global_stock_cap":"","_tribe_rsvp_for_event":"","_tribe_ticket_going_count":"","_tribe_ticket_not_going_count":"","_tribe_tickets_list":"[]","_tribe_ticket_has_attendee_info_fields":false,"footnotes":"","_tec_slr_enabled":"","_tec_slr_layout":""},"class_list":["post-1154","page","type-page","status-publish","hentry"],"ticketed":false,"_links":{"self":[{"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/pages\/1154","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/comments?post=1154"}],"version-history":[{"count":5,"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/pages\/1154\/revisions"}],"predecessor-version":[{"id":1216,"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/pages\/1154\/revisions\/1216"}],"wp:attachment":[{"href":"https:\/\/southsunindustries.com\/index.php\/wp-json\/wp\/v2\/media?parent=1154"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}