<!DOCTYPE html>

<html lang="bn">

<head>

  <meta charset="UTF-8" />

  <meta name="viewport" content="width=device-width, initial-scale=1.0" />

  <title>BD Number Format Checker + Old Robi Series Generator</title>

  <style>

    :root{--bg:#0b1222;--card:#111827;--muted:#94a3b8;--txt:#e5e7eb;--accent:#22c55e;--accent2:#3b82f6}

    *{box-sizing:border-box}

    body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial;background:linear-gradient(180deg,#0b1222,#0f172a);color:var(--txt)}

    .wrap{max-width:1100px;margin:24px auto;padding:16px}

    .card{background:rgba(17,24,39,.85);border:1px solid rgba(148,163,184,.25);backdrop-filter:blur(6px);border-radius:18px;padding:20px;box-shadow:0 10px 30px rgba(0,0,0,.35)}

    h1{font-size:26px;margin:0 0 6px}

    h2{font-size:18px;margin:18px 0 10px;color:#d1d5db}

    p, label, small{color:var(--muted)}

    .grid{display:grid;gap:12px}

    @media(min-width:960px){.grid.cols-2{grid-template-columns:1fr 1fr}}

    @media(min-width:960px){.grid.cols-3{grid-template-columns:1.1fr .9fr .9fr}}

    .row{display:flex;gap:10px;flex-wrap:wrap}

    input, textarea, select{width:100%;padding:12px 14px;border-radius:12px;border:1px solid rgba(148,163,184,.25);background:#0b1020;color:var(--txt);outline:none}

    input:focus, textarea:focus, select:focus{border-color:var(--accent2)}

    textarea{min-height:160px;resize:vertical}

    .btn{padding:11px 14px;border-radius:12px;border:1px solid rgba(148,163,184,.25);background:#0b1020;color:var(--txt);cursor:pointer;transition:.2s}

    .btn:hover{transform:translateY(-1px)}

    .btn.primary{background:linear-gradient(135deg,#22c55e,#16a34a);border:none;color:white}

    .btn.ghost{background:#0b1020}

    .btn.warn{background:linear-gradient(135deg,#ef4444,#dc2626);border:none;color:white}

    .muted{color:var(--muted)}

    .badge{display:inline-block;padding:6px 10px;border-radius:999px;background:#0b1020;border:1px solid rgba(148,163,184,.25);color:var(--muted);font-size:12px}

    .panel{border:1px solid rgba(148,163,184,.25);border-radius:14px;padding:12px;background:#0b1020}

    .listbox{min-height:220px}

    .stats{display:grid;grid-template-columns:repeat(2,1fr);gap:8px}

    @media(min-width:720px){.stats{grid-template-columns:repeat(4,1fr)}}

    .kpi{background:#0b1020;border:1px solid rgba(148,163,184,.25);border-radius:14px;padding:10px}

    .kpi b{font-size:18px;color:#fff}

    table{width:100%;border-collapse:collapse}

    th, td{border-bottom:1px solid rgba(148,163,184,.18);padding:8px 6px;text-align:left;font-size:14px}

    th{color:#cbd5e1}

    .footer{margin-top:10px;color:var(--muted);font-size:12px}

  </style>

</head>

<body>

  <div class="wrap">

    <div class="card">

      <h1>Bangladesh Number Format Checker + Old Robi Series Generator</h1>

      <p>এই টুলটি <b>ফরম্যাট চেক</b> ও <b>পুরনো সিরিজ থেকে ডেমো নম্বর জেনারেট</b> করার জন্য। এটি <b>ফেসবুকে আছে/নেই</b> এমন কোনো তথ্য <u>চেক করে না</u> এবং <u>করতে পারবে না</u>। প্রাইভেসি রুলস অনুযায়ী এটা অনুমোদিত নয়।</p>


      <div class="grid cols-2">

        <!-- LEFT: VALIDATOR -->

        <div class="panel">

          <h2>1) নম্বর ফরম্যাট চেক</h2>

          <label for="numbers">নিচে নাম্বার দিন (এক লাইন = এক নাম্বার)। +88 / 88 / 0 — সবই অটো-নরমালাইজ হবে:</label>

          <textarea id="numbers" placeholder="01893123456\n+8801893123456\n8801893123456\n01612345678"></textarea>

          <div class="row" style="margin-top:10px">

            <input type="file" id="csvFile" accept=".csv,.txt" />

            <button class="btn ghost" id="loadCsv">CSV লোড</button>

            <button class="btn primary" id="validate">Validate</button>

            <button class="btn ghost" id="copyValid">Copy Valid</button>

            <button class="btn ghost" id="exportValid">Export Valid CSV</button>

            <button class="btn warn" id="clearAll">Clear</button>

          </div>


          <div class="stats" style="margin-top:12px">

            <div class="kpi"><div class="muted">মোট ইনপুট</div><b id="k_total">0</b></div>

            <div class="kpi"><div class="muted">ভ্যালিড</div><b id="k_valid">0</b></div>

            <div class="kpi"><div class="muted">ইনভ্যালিড</div><b id="k_invalid">0</b></div>

            <div class="kpi"><div class="muted">ডুপ্লিকেট বাদ</div><b id="k_dedup">0</b></div>

          </div>


          <h3 style="margin-top:14px;color:#d1d5db">ভ্যালিড নাম্বার (নরমালাইজড)</h3>

          <textarea id="validOut" class="listbox" placeholder="ভ্যালিড নাম্বার এখানে..."></textarea>


          <h3 style="margin-top:14px;color:#d1d5db">ইনভ্যালিড / কারণ</h3>

          <div class="panel" style="max-height:200px;overflow:auto;background:#0b1026">

            <table id="badTable">

              <thead><tr><th>ইনপুট</th><th>কারণ</th></tr></thead>

              <tbody></tbody>

            </table>

          </div>

        </div>


        <!-- RIGHT: GENERATOR -->

        <div class="panel">

          <h2>2) Old Robi Series Generator (Demo)</h2>

          <label>সিরিজ সিলেক্ট করুন (ডিফল্ট পুরনো সিরিজ):</label>

          <select id="series" multiple size="7">

            <option value="01819" selected>01819 (Robi – old)</option>

            <option value="01820">01820 (Robi)</option>

            <option value="01821">01821 (Robi)</option>

            <option value="01822">01822 (Robi)</option>

            <option value="01892" selected>01892 (Robi – old)</option>

            <option value="01893" selected>01893 (Robi – old)</option>

            <option value="016">016 (Airtel BD)</option>

          </select>


          <div class="grid cols-3" style="margin-top:10px">

            <div>

              <label for="g_count">কতটি?</label>

              <input id="g_count" type="number" min="1" max="100000" value="500" />

            </div>

            <div>

              <label for="g_len">মোট ডিজিট</label>

              <input id="g_len" type="number" min="7" max="15" value="11" />

            </div>

            <div>

              <label for="g_dash">ফরম্যাট</label>

              <select id="g_dash">

                <option value="none" selected>018931234567</option>

                <option value="dash">01893-1234567</option>

                <option value="space">01893 1234567</option>

              </select>

            </div>

          </div>


          <div class="row" style="margin-top:10px">

            <button class="btn primary" id="gen">Generate</button>

            <button class="btn ghost" id="copyGen">Copy</button>

            <button class="btn ghost" id="exportGen">Export CSV</button>

            <span class="badge" id="g_stats">Ready</span>

          </div>


          <textarea id="genOut" class="listbox" placeholder="জেনারেটেড নাম্বার এখানে..."></textarea>


          <div class="footer">

            নোট: এগুলো <b>শুধু ডেমো</b> নম্বর। এগুলো কারো সঙ্গে যোগাযোগ/ভেরিফিকেশন চেষ্টা করবেন না।

          </div>

        </div>

      </div>


      <div class="footer" style="margin-top:14px">

        ⚠️ ডিসক্লেমার: এই টুল কোনোভাবেই Facebook/কোনো সার্ভিসে নাম্বার মিলিয়ে দেখার চেষ্টা করে না। এমন চেষ্টা করা প্রাইভেসি ও টার্মস ভায়োলেশন।

      </div>

    </div>

  </div>


  <script>

    // ------- Utils -------

    const $ = id => document.getElementById(id);


    const OPERATORS = {

      '013':'Grameenphone','017':'Grameenphone',

      '014':'Banglalink','019':'Banglalink',

      '015':'Teletalk',

      '016':'Airtel',

      '018':'Robi'

    };


    function normalizeOne(input){

      const raw = String(input).trim();

      if(!raw) return null;

      // keep digits only

      let d = raw.replace(/\D/g,'');

      // Remove leading country code 880 or +880

      if(d.startsWith('880')) d = d.slice(3);

      // Ensure leading 0 for local format

      if(d.length === 10 && !d.startsWith('0')) d = '0' + d;

      // Final checks

      if(d.length !== 11) return {ok:false, value:raw, reason:'ডিজিট ১১ না'};

      const op = d.slice(0,3);

      if(!OPERATORS[op]) return {ok:false, value:raw, reason:'অকার্যকর প্রিফিক্স'};

      return {ok:true, value:d, operator:OPERATORS[op]};

    }


    function parseLines(text){

      return text.split(/\r?\n/).map(s=>s.trim()).filter(Boolean);

    }


    function downloadCSV(filename, rows){

      const blob = new Blob([rows.join('\n')], {type:'text/csv;charset=utf-8;'});

      const a = document.createElement('a');

      a.href = URL.createObjectURL(blob);

      a.download = filename;

      document.body.appendChild(a);

      a.click();

      document.body.removeChild(a);

    }


    // ------- Validator -------

    $('loadCsv').addEventListener('click', ()=>{

      const file = $('csvFile').files?.[0];

      if(!file) return alert('CSV বা TXT ফাইল সিলেক্ট করুন');

      const fr = new FileReader();

      fr.onload = () => { $('numbers').value = String(fr.result||''); };

      fr.readAsText(file);

    });


    $('validate').addEventListener('click', ()=>{

      const lines = parseLines($('numbers').value);

      const badBody = $('badTable').querySelector('tbody');

      badBody.innerHTML = '';

      const validSet = new Set();

      const seen = new Set();

      let invalid = 0;

      let dedup = 0;


      for(const line of lines){

        if(seen.has(line)) { dedup++; continue; }

        seen.add(line);

        const res = normalizeOne(line);

        if(!res || !res.ok){

          invalid++;

          const tr = document.createElement('tr');

          const td1 = document.createElement('td'); td1.textContent = line;

          const td2 = document.createElement('td'); td2.textContent = res? res.reason : 'খালি লাইন';

          tr.append(td1, td2); badBody.appendChild(tr);

        } else {

          validSet.add(res.value);

        }

      }


      $('k_total').textContent = lines.length.toLocaleString();

      $('k_valid').textContent = validSet.size.toLocaleString();

      $('k_invalid').textContent = invalid.toLocaleString();

      $('k_dedup').textContent = dedup.toLocaleString();

      $('validOut').value = Array.from(validSet).join('\n');

    });


    $('copyValid').addEventListener('click', async ()=>{

      const val = $('validOut').value.trim();

      if(!val) return;

      try{ await navigator.clipboard.writeText(val); alert('Copied valid numbers'); }

      catch{ alert('Copy failed'); }

    });


    $('exportValid').addEventListener('click', ()=>{

      const val = $('validOut').value.trim();

      if(!val) return;

      const rows = ['number'];

      for(const n of val.split(/\n+/)) rows.push(n);

      downloadCSV(`valid_numbers_${Date.now()}.csv`, rows);

    });


    $('clearAll').addEventListener('click', ()=>{

      $('numbers').value=''; $('validOut').value='';

      $('k_total').textContent='0'; $('k_valid').textContent='0'; $('k_invalid').textContent='0'; $('k_dedup').textContent='0';

      $('badTable').querySelector('tbody').innerHTML='';

    });


    // ------- Generator -------

    function pad(num, size){ let s=String(num); while(s.length<size) s='0'+s; return s; }

    function mulberry32(a){return function(){let t=a+=0x6D2B79F5; t=Math.imul(t^t>>>15,t|1); t^=t+Math.imul(t^t>>>7,t|61); return ((t^t>>>14)>>>0)/4294967296;}}


    $('gen').addEventListener('click', ()=>{

      const opts = Array.from($('series').selectedOptions).map(o=>o.value);

      if(opts.length===0) return alert('কমপক্ষে একটি সিরিজ সিলেক্ট করুন');

      const totalLen = Math.max(7, Math.min(15, parseInt($('g_len').value||'11',10)));

      const count = Math.max(1, Math.min(100000, parseInt($('g_count').value||'1000',10)));

      const fmt = $('g_dash').value;


      const rng = mulberry32(Date.now() & 0xffffffff);

      const out = [];

      const perSeries = Math.ceil(count / opts.length);


      for(const prefix of opts){

        const p = prefix.replace(/\D/g,'');

        const remain = totalLen - p.length;

        if(remain <= 0) continue;

        const maxComb = Math.pow(10, remain);

        const needed = Math.min(perSeries, maxComb);

        const set = new Set();

        while(set.size < needed){

          set.add(pad(Math.floor(rng()*maxComb), remain));

        }

        for(const tail of set){

          let n = p + tail;

          if(fmt==='dash') n = n.slice(0,p.length)+'-'+n.slice(p.length);

          else if(fmt==='space') n = n.slice(0,p.length)+' '+n.slice(p.length);

          out.push(n);

        }

      }


      $('genOut').value = out.slice(0, count).join('\n');

      $('g_stats').textContent = `Generated ${Math.min(count,out.length).toLocaleString()} numbers`;

    });


    $('copyGen').addEventListener('click', async ()=>{

      const val = $('genOut').value.trim(); if(!val) return;

      try{ await navigator.clipboard.writeText(val); alert('Copied'); } catch{ alert('Copy failed'); }

    });


    $('exportGen').addEventListener('click', ()=>{

      const val = $('genOut').value.trim(); if(!val) return;

      const rows = ['number']; for(const n of val.split(/\n+/)) rows.push(n.replace(/\s|-/g,''));

      downloadCSV(`generated_${Date.now()}.csv`, rows);

    });

  </script>

</body>

</html>


Comments

Popular posts from this blog