• דף הבית
    • אינדקס קישורים
    • פוסטים אחרונים
    • משתמשים
    • חיפוש בהגדרות המתקדמות
    • חיפוש גוגל בפורום
    • ניהול המערכת
    • ניהול המערכת - שרת private
    • הרשמה
    • התחברות
    1. דף הבית
    2. ישראל10
    י מנותק
    • פרופיל
    • עוקב אחרי 0
    • עוקבים 2
    • נושאים 45
    • פוסטים 252
    • קבוצות 0

    ישראל10

    @ישראל10

    96
    מוניטין
    77
    צפיות בפרופיל
    252
    פוסטים
    2
    עוקבים
    0
    עוקב אחרי
    תאריך הצטרפות
    נראה לאחרונה

    ישראל10 הפסקת מעקב מעקב

    הפוסטים הטובים ביותר שנוצרו על ידי ישראל10

    • חדש!!! קו ק"ש ללא עלות

      חדש!
      ניתן לקבל צינטוק 10-15 דקות לפני סו"ז ק"ש לפי שיטת הגר"א ובעל התניא, ללא עלות!!!
      המספר הוא
      0772049638
      אשמח אם תפיצו את המספר.
      תודה

      עריכה
      כעת יש סקר לעוד שני אופציות של תזכורות כאן

      פורסם בעזרה הדדית למשתמשים מתקדמים
      י
      ישראל10
    • יחידות תמורת דקות

      כיום, אם יש לי רעיון לפתוח איזה מערכת ואני יודע שזה לא יגיע למספר דקות גבוה, או שאין לי עוסק מורשה\פטור ואין לי כוח להיכנס לכל העסק הזה, אני לא יקבל תשלום על המערכת, סיכוי גדול שאני לא יפתח אותו, מכיוון שאני לא מרוויח כלום על זה. [אא"כ מדובר במערכת שאני צריך את עצם הקו].
      חשבתי על רעיון בנושא זה, שיהיה אפשר לקבל יחידות תמורת דקות.
      כלומר, יהיה מינימום של דקות חודשיות, אבל לא מספר גבוה מאוד כמו שצריך בשביל לקבל תשלום, [נגיד 5.000 דקות חודשיות] ועל כל מספר מסוים של דקות, יקבלו יחידות, לדוג', על כל 150 דקות יקבלו יחידה. ומעל 10.000 דקות יקבלו על כל 100 דק' יחידה וכו', כמו בתשלום כספי כיום.

      [כמו כן, אולי יהיה ניתן לעשות את זה על וירטואל פלוס, שעל כל מספר מסוים של דקות, יקבלו יחידות.]
      תודה מראש, אשמח לתגובות.
      @ימות-המשיח @שמואל

      פורסם בבקשות לפיתוח
      י
      ישראל10
    • RE: רשימת קווים מומלצים

      קו של בייבי סיטר, משהו מטורף.לנשואים בלבד... 😉
      0772609000

      פורסם בעזרה הדדית למשתמשים מתקדמים
      י
      ישראל10
    • זמני היום מדויק + חיפוש ערים ותאריכים בזיהוי דיבור.

      חדש!!
      ניתן לשמוע את זמני היום בצורה מדויקת, וכן חיפוש ערים ותאריכים לפי זיהוי דיבור. במערכת שהזמן גרמא [השולחת תזכורות ללא עלות מספר דקות [לפי בחירה שלכם] לפני זמני היום, ] שלוחה 4.
      המספר הוא 0795686170

      פורסם בטיפים עצות והדגמות מהמשתמשים
      י
      ישראל10
    • רציתם??? קיבלתם!!! קו ק"ש לשיטת המג"א והגר"א, וזמן תפילה, וגם .... לשקיעת החמה!!!!

      @0795702821 וכלל משמשי הקו

      רציתם? קיבלתם!!!

      ניתן לקבל גם תזכורות לסו"ז ק"ש לשיטת הגר"א, וגם לשיטת המג"א!!!! וגם לסו"ז תפילה לשיטת הגר"א, וגם.... לפני שקיעת החמה!!!!!
      חייגו עכשיו 0772049638
      וכל זה ללא עלות!!!

      פורסם בעזרה הדדית למשתמשים מתקדמים
      י
      ישראל10
    • RE: חדש!!! קו ק"ש ללא עלות

      סתם בשביל העידכון, יש יותר מ1200 שמקבלים תזכורת כל יום.

      פורסם בעזרה הדדית למשתמשים מתקדמים
      י
      ישראל10
    • RE: חדש!!! קו ק"ש ללא עלות

      כידוע בימי בין הזמנים, הזמני היום יותר מטושטשים... והקו יותר נצרך.
      ניתן להצטרף רק לבין הזמנים, ובסוף בין הזמנים להסיר את עצמכם מרשימת התפוצה.
      כמובן נשמח עם תיידעו את בני משפחתכם וכו', להרבות זכויות.
      בהזדמנות זאת, ברצוני להודות לחברת @ימות-המשיח על הפלטפורמה הנפלאה, שעוזרת כ"כ-ובפרט לציבור החרדי.
      תמשיכו להצליח-ותצליחו להמשיך.

      פורסם בעזרה הדדית למשתמשים מתקדמים
      י
      ישראל10
    • RE: חדש!!! אנקי קול, לזכור הכל

      מערכת מושלמת!!!!
      כל הכבוד, זה פשוט מושלם.
      אני התחלתי להשתמש בזה, פשוט תענוג כל רגע...

      פורסם בעזרה הדדית למשתמשים מתקדמים
      י
      ישראל10
    • RE: פניות תח"צ בטלפון

      @שמואל-ש @מתנסה-php-api @WIZNITZ אדרבה.
      תרימו את הכפפה ביחד.
      [אם בהמשך יצטרכו תשלום סמלי בשביל שרת או כיוצא בזה, אני מוכן לשלם].

      פורסם בעזרה הדדית למשתמשים מתקדמים
      י
      ישראל10
    • וירטואל + למספר נייח

      חשבתי שאולי יהיה אפשר לעשות שיהיה וירטואל + לנייח.
      הרווח בזה
      בווירטואל לנייד, אפשר להוציא שיחות לנייח ללא עלות יחידות.
      אז בווירטואל למספר נייח יהיה אפשר לקבל שיחות מנייד ללא עלות, מכיוון שזה אותו רעיון, מספר נייד שמחייג לווירטואל ויוצא למספר נייח.
      תודה מראש

      פורסם בבקשות לפיתוח
      י
      ישראל10

    פוסטים אחרונים שנוצרו על ידי ישראל10

    • RE: ממשק HTML לבדיקת כמות מאזינים בו זמנית (ערוצים)

      @מסובך-מאוד אני מעלה את זה וזה לא עולה.
      מעלה את הקוד, מי שיודע איך להעלות את זה בקובץ, מוזמן.

      <!doctype html>
      <html lang="he" dir="rtl">
      <head>
      <meta charset="utf-8">
      <meta name="viewport" content="width=device-width,initial-scale=1">
      <title>ספר מספרים - ימות המשיח</title>
      <style>
      :root{--bg:#f3f5f4;--surface:#fff;--ink:#14201c;--muted:#5d6b66;--line:#d9e0dd;--accent:#0f7a5c;--accent-soft:#e1f2ec;--warn:#b45309;--bad:#b42318;color-scheme:light}
      @media (prefers-color-scheme:dark){:root{--bg:#0e1513;--surface:#16201d;--ink:#e6eeeb;--muted:#93a39d;--line:#2a3733;--accent:#3fc596;--accent-soft:#183a2f;--warn:#f0a454;--bad:#f2786d;color-scheme:dark}}
      *{box-sizing:border-box}[hidden]{display:none!important}
      body{margin:0;background:var(--bg);color:var(--ink);font:16px/1.55 "Assistant",system-ui,-apple-system,"Segoe UI",Arial,sans-serif;padding:28px 16px 60px}
      .wrap{max-width:980px;margin-inline:auto;display:grid;gap:18px}
      h1{margin:0;font-size:clamp(1.5rem,4vw,2.1rem)}h2{margin:0;font-size:1.15rem}
      .lede,.muted{color:var(--muted)}.small{font-size:.86rem}
      .card{background:var(--surface);border:1px solid var(--line);border-radius:14px;padding:20px;display:grid;gap:14px;min-width:0}
      .row{display:flex;flex-wrap:wrap;gap:12px;align-items:end}
      .field{display:grid;gap:4px;flex:1 1 180px;min-width:0}
      label{font-size:.85rem;font-weight:600;color:var(--muted)}
      input,select{font:inherit;color:var(--ink);background:var(--bg);border:1px solid var(--line);border-radius:9px;padding:9px 11px;width:100%}
      input.ltr{direction:ltr;text-align:left}
      button{font:inherit;font-weight:700;border-radius:9px;padding:9px 16px;cursor:pointer;border:1px solid var(--accent);background:var(--accent);color:var(--surface)}
      button.ghost{background:transparent;color:var(--accent)}button:disabled{opacity:.5;cursor:default}
      .seg{display:inline-flex;border:1px solid var(--line);border-radius:10px;padding:3px;gap:3px;background:var(--bg)}
      .seg button{border:0;background:transparent;color:var(--muted);padding:6px 14px;border-radius:7px}
      .seg button[aria-pressed="true"]{background:var(--surface);color:var(--ink)}
      .status{font-size:.92rem;padding:9px 12px;border-radius:9px;background:var(--accent-soft)}
      .status.err{border-inline-start:3px solid var(--bad)}.status.warn{border-inline-start:3px solid var(--warn)}
      .kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:12px}
      .kpi{border:1px solid var(--line);border-radius:12px;padding:12px 14px;display:grid;gap:2px}
      .kpi .v{font:700 1.8rem/1.1 ui-monospace,Consolas,monospace;direction:ltr;text-align:start}
      .kpi .k{font-size:.85rem;color:var(--muted);font-weight:600}
      .scroll{overflow-x:auto}
      table{border-collapse:collapse;width:100%;font-size:.9rem}
      th,td{text-align:start;padding:6px 10px;border-bottom:1px solid var(--line);white-space:nowrap}
      th{font-size:.8rem;color:var(--muted)}
      td.num{font-family:ui-monospace,Consolas,monospace;direction:ltr;text-align:end}
      progress{width:100%;height:10px}
      </style>
      </head>
      <body>
      <div class="wrap">
      <header>
        <h1>ספר מספרים</h1>
        <p class="lede">שולף את כל לוגי הכניסות של המערכת, מאחד לפי מספר טלפון, ומייצא לאקסל: מי התקשר, מאיזה אזור, באילו שעות, ומאז מתי.</p>
      </header>
      
      <section class="card">
        <div class="row" style="justify-content:space-between">
          <h2>חיבור למערכת</h2>
          <div class="seg" role="group" aria-label="שיטת התחברות">
            <button type="button" id="m-pass" aria-pressed="true">מספר מערכת + סיסמה</button>
            <button type="button" id="m-token" aria-pressed="false">טוקן / API KEY</button>
          </div>
        </div>
        <form id="conn" class="row" autocomplete="off">
          <div class="field" id="f-num"><label for="num">מספר מערכת</label><input id="num" class="ltr" inputmode="numeric" placeholder="0771234567"></div>
          <div class="field" id="f-pass"><label for="pass">סיסמת ניהול</label><input id="pass" class="ltr" type="password"></div>
          <div class="field" id="f-token" hidden><label for="token">טוקן או מפתח API</label><input id="token" class="ltr" type="password"></div>
          <button type="submit" id="btn-conn">התחבר</button>
        </form>
        <div id="conn-status" class="status" hidden></div>
        <p class="small muted" style="margin:0">הפרטים נשלחים ישירות מהדפדפן לשרת של ימות המשיח (call2all.co.il) ולא נשמרים בשום מקום.</p>
      </section>
      
      <section class="card">
        <h2>שליפה</h2>
        <div class="row">
          <div class="field"><label for="from">מחודש (ריק = הכי ישן שיש)</label><input id="from" type="month"></div>
          <div class="field"><label for="to">עד חודש (ריק = הכי חדש)</label><input id="to" type="month"></div>
          <button type="button" id="btn-pull" disabled>משוך את כל ההיסטוריה</button>
        </div>
        <progress id="prog" value="0" max="1" hidden></progress>
        <div id="pull-status" class="status" hidden></div>
      
        <details>
          <summary style="cursor:pointer;font-weight:700">אופציונלי: קובץ התאמה של טלפון לעיר ולשם</summary>
          <p class="small muted">קובץ CSV עם כותרות: <b>טלפון</b>, <b>עיר</b>, ואפשר גם <b>שם</b> (או phone, city, name). המספרים שנמצאים בו יקבלו עיר ושם בעמודות נפרדות באקסל. בלי קובץ כזה העמודה "אזור" מבוססת על הקידומת בלבד.</p>
          <input id="mapfile" type="file" accept=".csv,.txt">
          <div id="map-status" class="small muted"></div>
        </details>
        <details>
          <summary style="cursor:pointer;font-weight:700">אין גישה דרך ה-API? העלה קבצי לוג ידנית</summary>
          <p class="small muted">אפשר לבחור כמה קבצי LogFolderEnterExit (CSV או ymgr) יחד. שמות הקבצים צריכים להכיל את החודש כדי שהסדר יהיה נכון.</p>
          <input id="logfiles" type="file" accept=".csv,.ymgr,.txt" multiple>
        </details>
      </section>
      
      <section class="card" id="res" hidden>
        <div class="row" style="justify-content:space-between">
          <h2>תוצאה</h2>
          <div class="row" style="gap:8px">
            <button type="button" id="btn-xlsx">הורד Excel</button>
            <button type="button" class="ghost" id="btn-csv">הורד CSV</button>
          </div>
        </div>
        <div id="xlsx-warn" class="status warn" hidden></div>
        <div class="kpis" id="kpis"></div>
        <div class="scroll"><table><thead><tr><th>טלפון</th><th>אזור</th><th>עיר</th><th>ראשון</th><th>אחרון</th><th>ותק (ימים)</th><th>שיחות</th><th>חלק יום עיקרי</th><th>סטטוס</th></tr></thead><tbody id="prev"></tbody></table></div>
        <p class="small muted" style="margin:0">מוצגים 100 המספרים עם הכי הרבה שיחות. הקובץ המלא כולל את כולם.</p>
      </section>
      </div>
      
      <script src="https://cdnjs.cloudflare.com/ajax/libs/exceljs/4.4.0/exceljs.min.js" async></script>
      <script>
      /* ===== ליבה: פענוח לוג, צבירה לפי מספר, בניית חוברת אקסל ===== */
      const T = (() => {
        const ANON = new Set(['', '0', 'unknown', 'anonymous', 'חסוי', 'private', 'restricted', 'blocked']);
        const isAnon = p => ANON.has(String(p || '').trim().toLowerCase());
        const DAY = 86400000;
      
        function parseYmgrLine(line) {
          const o = {};
          for (const part of line.split('%')) { const i = part.indexOf('#'); if (i > 0) o[part.slice(0, i).trim()] = part.slice(i + 1).trim(); }
          return o;
        }
        function parseCSV(text) {
          const rows = []; let row = [], cur = '', q = false;
          for (let i = 0; i < text.length; i++) {
            const c = text[i];
            if (q) { if (c === '"') { if (text[i + 1] === '"') { cur += '"'; i++; } else q = false; } else cur += c; }
            else if (c === '"') q = true;
            else if (c === ',') { row.push(cur); cur = ''; }
            else if (c === '\n' || c === '\r') { if (c === '\r' && text[i + 1] === '\n') i++; row.push(cur); cur = ''; if (row.some(x => x.trim() !== '')) rows.push(row); row = []; }
            else cur += c;
          }
          row.push(cur); if (row.some(x => x.trim() !== '')) rows.push(row);
          return rows;
        }
        const HEAD_MAP = [
          ['Phone', /^(phone|טלפון|מספר טלפון|מספר הטלפון|טלפון המתקשר|מספר טלפון של המתקשר)$/i],
          ['Folder', /^(folder|תיקיה|תיקייה|שלוחה|תיקיה - שלוחה במערכת)$/i],
          ['EnterDate', /^(enterdate|תאריך|תאריך לועזי|תאריך כניסה)$/i],
          ['EnterTime', /^(entertime|שעת כניסה|שעת הכניסה|שעה)$/i],
          ['ExitTime', /^(exittime|שעת יציאה|שעת היציאה)$/i],
          ['TimeTotal', /^(timetotal|סך הכל זמן האזנה|סה"כ זמן האזנה|זמן האזנה|משך)$/i],
        ];
        function parseLogText(text) {
          text = String(text).replace(/^\uFEFF/, '');
          const lines = text.split(/\r?\n/).filter(l => l.trim());
          if (!lines.length) return [];
          const ymgrLike = lines.slice(0, 20).filter(l => /[A-Za-z]+#/.test(l) && l.includes('%')).length;
          if (ymgrLike >= Math.min(3, lines.length)) return lines.map(parseYmgrLine);
          const rows = parseCSV(text);
          if (rows.length < 2) return [];
          const head = rows[0].map(h => h.trim()), idx = {};
          head.forEach((h, i) => { for (const [k, re] of HEAD_MAP) if (idx[k] === undefined && re.test(h)) idx[k] = i; });
          return rows.slice(1).map(r => { const o = {}; for (const k in idx) o[k] = (r[idx[k]] || '').trim(); return o; });
        }
        function parseDate(s) {
          if (!s) return null; s = String(s).trim();
          let y, m, d, mm;
          if ((mm = s.match(/^(\d{4})[-\/.](\d{1,2})[-\/.](\d{1,2})/))) { y = +mm[1]; m = +mm[2]; d = +mm[3]; }
          else if ((mm = s.match(/^(\d{1,2})[-\/.](\d{1,2})[-\/.](\d{2,4})/))) { d = +mm[1]; m = +mm[2]; y = +mm[3]; if (y < 100) y += 2000; }
          else return null;
          if (m < 1 || m > 12 || d < 1 || d > 31) return null;
          return [y, m, d];
        }
        function parseTime(s) {
          if (!s) return null; s = String(s).trim();
          if (s.includes(' ')) s = s.slice(s.lastIndexOf(' ') + 1);
          const m = s.match(/^(\d{1,2})[:\-.](\d{2})(?:[:\-.](\d{2}))?$/);
          if (!m) return null;
          const h = +m[1], mi = +m[2], se = +(m[3] || 0);
          if (h > 23 || mi > 59 || se > 59) return null;
          return h * 3600 + mi * 60 + se;
        }
        function parseDur(s) {
          if (s === undefined || s === null) return null; s = String(s).trim(); if (s === '') return null;
          if (/^\d+(\.\d+)?$/.test(s)) return Math.round(+s);
          const m = s.match(/^(\d+):(\d{2})(?::(\d{2}))?$/);
          if (m) return m[3] !== undefined ? (+m[1]) * 3600 + (+m[2]) * 60 + (+m[3]) : (+m[1]) * 60 + (+m[2]);
          return null;
        }
        const at = (d, sec) => new Date(d[0], d[1] - 1, d[2], Math.floor(sec / 3600), Math.floor(sec / 60) % 60, sec % 60).getTime();
      
        /* טלפון -> צורה אחידה: 0501234567 / 021234567 / +<מספר חו"ל> / '' אם חסוי */
        function normPhone(raw) {
          if (isAnon(raw)) return '';
          let d = String(raw).replace(/\D/g, '');
          if (!d) return '';
          if (d.startsWith('00972')) d = '0' + d.slice(5);
          else if (d.startsWith('972') && d.length >= 11) d = '0' + d.slice(3);
          else if (d.startsWith('00')) return '+' + d.slice(2);
          else if (d.length === 9 && d[0] === '5') d = '0' + d;
          return d;
        }
        const LAND = { '02': 'ירושלים והסביבה', '03': 'גוש דן / מרכז', '04': 'צפון וחיפה', '08': 'שפלה ודרום', '09': 'השרון' };
        function phoneInfo(p) {
          if (p[0] === '+') return { region: 'חו"ל', type: 'חו"ל' };
          if (/^05\d{8}$/.test(p)) return { region: 'נייד (אין אזור)', type: 'נייד' };
          if (/^0[23489]\d{7}$/.test(p)) return { region: LAND[p.slice(0, 2)], type: 'קווי' };
          if (/^07\d{8}$/.test(p)) return { region: 'קו ארצי / VoIP (07x)', type: 'קווי ארצי' };
          return { region: 'לא מזוהה', type: 'לא מזוהה' };
        }
      
        function toIntervals(records) {
          const out = [], diag = { rows: records.length, ok: 0, bad: 0 };
          for (const r of records) {
            const d = parseDate(r.EnterDate), t0 = parseTime(r.EnterTime);
            if (!d || t0 === null) { diag.bad++; continue; }
            const start = at(d, t0), t1 = parseTime(r.ExitTime), dur = parseDur(r.TimeTotal);
            let end = null;
            if (t1 !== null && t1 >= t0) end = at(d, t1);
            else if (t1 !== null) {
              if (dur !== null) end = start + dur * 1000;
              else if (t0 - t1 >= 12 * 3600) end = at(d, t1) + DAY;
              else end = start;
            } else if (dur !== null) end = start + dur * 1000;
            if (end === null) { diag.bad++; continue; }
            end = Math.max(end, start + 1000);
            out.push({ phone: normPhone(r.Phone), folder: String(r.Folder || '').trim(), start, end }); diag.ok++;
          }
          return { intervals: out, diag };
        }
        function mergeCalls(intervals, gapMs = 3000) {
          const byPhone = new Map(), calls = [];
          for (const iv of intervals) {
            if (isAnon(iv.phone)) { calls.push({ ...iv, folders: [iv.folder] }); continue; }
            if (!byPhone.has(iv.phone)) byPhone.set(iv.phone, []);
            byPhone.get(iv.phone).push(iv);
          }
          for (const [, list] of byPhone) {
            list.sort((a, b) => a.start - b.start);
            let cur = { ...list[0], folders: [list[0].folder] };
            for (let i = 1; i < list.length; i++) {
              const n = list[i];
              if (n.start <= cur.end + gapMs) { cur.end = Math.max(cur.end, n.end); if (!cur.folders.includes(n.folder)) cur.folders.push(n.folder); }
              else { calls.push(cur); cur = { ...n, folders: [n.folder] }; }
            }
            calls.push(cur);
          }
          return calls;
        }
      
        /* ----- צבירה ----- */
        const BUCKETS = ['לילה (00-06)', 'בוקר (06-12)', 'צהריים ואחה"צ (12-18)', 'ערב (18-24)'];
        const bucketOf = h => h < 6 ? 0 : h < 12 ? 1 : h < 18 ? 2 : 3;
        const mkey = t => { const d = new Date(t); return d.getFullYear() + '-' + String(d.getMonth() + 1).padStart(2, '0'); };
        const dnum = t => { const d = new Date(t); return Math.floor(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate()) / DAY); };
      
        function newAgg() {
          return { phones: new Map(), months: new Map(), heat: Array.from({ length: 7 }, () => new Array(24).fill(0)), anonCalls: 0, rows: 0, bad: 0, files: 0 };
        }
        function addRecords(agg, records) {
          const { intervals, diag } = toIntervals(records);
          agg.rows += diag.rows; agg.bad += diag.bad; agg.files++;
          for (const c of mergeCalls(intervals)) {
            const dt = new Date(c.start), h = dt.getHours();
            const mk = mkey(c.start);
            let m = agg.months.get(mk); if (!m) { m = { calls: 0, phones: new Set() }; agg.months.set(mk, m); }
            m.calls++;
            agg.heat[dt.getDay()][h]++;
            if (isAnon(c.phone)) { agg.anonCalls++; continue; }
            m.phones.add(c.phone);
            let r = agg.phones.get(c.phone);
            if (!r) { r = { phone: c.phone, first: c.start, last: c.start, calls: 0, totalMs: 0, b: [0, 0, 0, 0], hours: new Uint32Array(24), days: new Set(), folders: new Map() }; agg.phones.set(c.phone, r); }
            if (c.start < r.first) r.first = c.start;
            if (c.start > r.last) r.last = c.start;
            r.calls++; r.totalMs += c.end - c.start; r.b[bucketOf(h)]++; r.hours[h]++; r.days.add(dnum(c.start));
            for (const f of c.folders) r.folders.set(f, (r.folders.get(f) || 0) + 1);
          }
        }
        const argmax = a => { let bi = 0; for (let i = 1; i < a.length; i++) if (a[i] > a[bi]) bi = i; return bi; };
      
        function finalize(agg, nowMs, cityMap) {
          cityMap = cityMap || new Map();
          const rows = [];
          for (const r of agg.phones.values()) {
            const info = phoneInfo(r.phone), cm = cityMap.get(r.phone) || {};
            const sinceLast = Math.max(0, Math.floor((nowMs - r.last) / DAY));
            let mainF = '', mx = 0; for (const [f, n] of r.folders) if (n > mx) { mx = n; mainF = f; }
            rows.push({
              phone: r.phone, region: info.region, type: info.type, city: cm.city || '', name: cm.name || '',
              first: r.first, last: r.last,
              tenureDays: Math.max(0, Math.floor((nowMs - r.first) / DAY)), sinceLast,
              spanDays: Math.floor((r.last - r.first) / DAY),
              activeDays: r.days.size, calls: r.calls, totalHours: r.totalMs / 3600000, avgMin: r.totalMs / 60000 / r.calls,
              b: r.b, mainBucket: BUCKETS[argmax(r.b)], peakHour: argmax(r.hours),
              status: sinceLast <= 30 ? 'פעיל (עד 30 יום)' : sinceLast <= 90 ? 'מתקרר (30-90 יום)' : 'רדום (מעל 90 יום)',
              folder: mainF
            });
          }
          rows.sort((a, b) => b.calls - a.calls);
          const firstByMonth = new Map();
          for (const r of rows) { const k = mkey(r.first); firstByMonth.set(k, (firstByMonth.get(k) || 0) + 1); }
          const months = [...new Set([...agg.months.keys(), ...firstByMonth.keys()])].sort().map(k => ({
            month: k, calls: agg.months.get(k) ? agg.months.get(k).calls : 0, active: agg.months.get(k) ? agg.months.get(k).phones.size : 0, fresh: firstByMonth.get(k) || 0
          }));
          const regions = new Map();
          for (const r of rows) {
            let g = regions.get(r.region); if (!g) { g = { region: r.region, numbers: 0, calls: 0, hours: 0, tenure: 0, active: 0 }; regions.set(r.region, g); }
            g.numbers++; g.calls += r.calls; g.hours += r.totalHours; g.tenure += r.tenureDays; if (r.sinceLast <= 30) g.active++;
          }
          const regionList = [...regions.values()].sort((a, b) => b.numbers - a.numbers);
          const bucketList = BUCKETS.map((name, i) => ({ name, calls: rows.reduce((s, r) => s + r.b[i], 0), mainFor: rows.filter(r => r.mainBucket === name).length }));
          return {
            rows, months, regions: regionList, buckets: bucketList, heat: agg.heat,
            summary: {
              numbers: rows.length, calls: rows.reduce((s, r) => s + r.calls, 0), anonCalls: agg.anonCalls, logRows: agg.rows, badRows: agg.bad, files: agg.files,
              first: rows.length ? Math.min(...rows.map(r => r.first)) : null, last: rows.length ? Math.max(...rows.map(r => r.last)) : null,
              active30: rows.filter(r => r.sinceLast <= 30).length, mapped: rows.filter(r => r.city).length,
              onceOnly: rows.filter(r => r.calls === 1).length, now: nowMs
            }
          };
        }
      
        function parseCityMap(text) {
          const rows = parseCSV(String(text).replace(/^\uFEFF/, ''));
          if (rows.length < 2) return new Map();
          const head = rows[0].map(h => h.trim().toLowerCase());
          const ip = head.findIndex(h => /^(phone|טלפון|מספר|מספר טלפון)$/.test(h));
          const ic = head.findIndex(h => /^(city|עיר|יישוב|ישוב)$/.test(h));
          const inm = head.findIndex(h => /^(name|שם)$/.test(h));
          const m = new Map();
          if (ip < 0) return m;
          for (const r of rows.slice(1)) { const p = normPhone(r[ip]); if (p) m.set(p, { city: ic >= 0 ? (r[ic] || '').trim() : '', name: inm >= 0 ? (r[inm] || '').trim() : '' }); }
          return m;
        }
      
        /* ----- ייצוא ----- */
        const xd = ms => new Date(ms - new Date(ms).getTimezoneOffset() * 60000); // ExcelJS כותב UTC, אז מזיזים כדי שיוצג שעון מקומי
        const DOW = ['ראשון', 'שני', 'שלישי', 'רביעי', 'חמישי', 'שישי', 'שבת'];
        const MAIN_COLS = [
          ['טלפון', 16, '@'], ['אזור (לפי קידומת)', 20], ['סוג קו', 11], ['עיר (מקובץ התאמה)', 18], ['שם (מקובץ התאמה)', 18],
          ['הופעה ראשונה', 17, 'dd/mm/yyyy hh:mm'], ['הופעה אחרונה', 17, 'dd/mm/yyyy hh:mm'],
          ['ותק (ימים מההופעה הראשונה)', 15, '#,##0'], ['ימים מאז האחרונה', 12, '#,##0'], ['ימים בין ראשונה לאחרונה', 13, '#,##0'], ['ימים פעילים', 10, '#,##0'], ['סטטוס', 18],
          ['שיחות', 9, '#,##0'], ['סה"כ האזנה (שעות)', 12, '#,##0.0'], ['ממוצע לשיחה (דקות)', 12, '#,##0.0'],
          ['שיחות בלילה (00-06)', 11, '#,##0'], ['שיחות בבוקר (06-12)', 11, '#,##0'], ['שיחות בצהריים (12-18)', 11, '#,##0'], ['שיחות בערב (18-24)', 11, '#,##0'],
          ['חלק יום עיקרי', 20], ['שעה נפוצה', 9, '0'], ['שלוחה עיקרית', 14, '@']
        ];
        const mainRow = r => [r.phone, r.region, r.type, r.city, r.name, xd(r.first), xd(r.last), r.tenureDays, r.sinceLast, r.spanDays, r.activeDays, r.status,
          r.calls, +r.totalHours.toFixed(2), +r.avgMin.toFixed(2), r.b[0], r.b[1], r.b[2], r.b[3], r.mainBucket, r.peakHour, r.folder];
      
        function buildWorkbook(ExcelJS, res) {
          const wb = new ExcelJS.Workbook(); wb.creator = 'ספר מספרים'; wb.created = new Date();
          const hdr = ws => { const r = ws.getRow(1); r.font = { bold: true, color: { argb: 'FFFFFFFF' } }; r.fill = { type: 'pattern', pattern: 'solid', fgColor: { argb: 'FF0F7A5C' } }; r.alignment = { vertical: 'middle', horizontal: 'center', wrapText: true }; r.height = 34; };
          const s = res.summary, fd = ms => ms ? xd(ms) : '';
      
          const w1 = wb.addWorksheet('סיכום', { views: [{ rightToLeft: true }] });
          w1.columns = [{ width: 38 }, { width: 24 }];
          const kv = [
            ['נוצר בתאריך', xd(s.now)], ['מספרי טלפון שונים', s.numbers], ['שיחות (אחרי איחוד מעברי שלוחה)', s.calls], ['שיחות ממספר חסוי (לא בטבלת המספרים)', s.anonCalls],
            ['מספרים שהתקשרו פעם אחת בלבד', s.onceOnly], ['מספרים פעילים ב-30 הימים האחרונים', s.active30], ['מספרים עם עיר מקובץ ההתאמה', s.mapped],
            ['ההופעה הראשונה בלוגים', fd(s.first)], ['ההופעה האחרונה בלוגים', fd(s.last)], ['קבצי לוג שנקראו', s.files], ['שורות לוג', s.logRows], ['שורות שלא נקראו', s.badRows]
          ];
          kv.forEach(([k, v]) => { const r = w1.addRow([k, v]); r.getCell(1).font = { bold: true }; if (v instanceof Date) r.getCell(2).numFmt = 'dd/mm/yyyy hh:mm'; else if (typeof v === 'number') r.getCell(2).numFmt = '#,##0'; r.getCell(2).alignment = { horizontal: 'right' }; });
          w1.addRow([]);
          const note = w1.addRow(['הערות']); note.font = { bold: true };
          ['* "ותק" = כמה זמן עבר מההופעה הראשונה של המספר בלוגים ועד יום יצירת הקובץ. לא יודעים מתי נרשם בפועל, רק מתי נראה לראשונה בלוג שנשמר במערכת.',
           '* "אזור" נקבע לפי הקידומת בלבד. מספר נייד לא נושא מידע על עיר, ומספר קווי נושא רק אזור כללי.',
           '* חלק היום נקבע לפי שעת תחילת השיחה.'].forEach(t => { const r = w1.addRow([t]); r.alignment = { wrapText: true }; w1.mergeCells(r.number, 1, r.number, 2); r.height = 44; });
      
          const w2 = wb.addWorksheet('מספרים', { views: [{ rightToLeft: true, state: 'frozen', xSplit: 1, ySplit: 1 }] });
          w2.columns = MAIN_COLS.map(c => ({ header: c[0], width: c[1], style: c[2] ? { numFmt: c[2] } : {} }));
          hdr(w2);
          w2.addRows(res.rows.map(mainRow));
          w2.autoFilter = { from: { row: 1, column: 1 }, to: { row: 1, column: MAIN_COLS.length } };
      
          const w3 = wb.addWorksheet('לפי אזור', { views: [{ rightToLeft: true, state: 'frozen', ySplit: 1 }] });
          w3.columns = [['אזור', 26], ['מספרים', 12], ['שיחות', 12], ['שעות האזנה', 14], ['ותק ממוצע (ימים)', 16], ['פעילים ב-30 יום', 14], ['% מכלל המספרים', 14]].map(c => ({ header: c[0], width: c[1] }));
          hdr(w3);
          res.regions.forEach(g => w3.addRow([g.region, g.numbers, g.calls, +g.hours.toFixed(1), Math.round(g.tenure / g.numbers), g.active, g.numbers / Math.max(1, s.numbers)]));
          w3.getColumn(7).numFmt = '0.0%';
      
          const w4 = wb.addWorksheet('שעות ביום', { views: [{ rightToLeft: true, state: 'frozen', xSplit: 1, ySplit: 1 }] });
          w4.addRow(['יום \\ שעה', ...Array.from({ length: 24 }, (_, h) => String(h).padStart(2, '0'))]); hdr(w4);
          w4.getColumn(1).width = 12; for (let c = 2; c <= 25; c++) w4.getColumn(c).width = 7;
          res.heat.forEach((row, d) => w4.addRow([DOW[d], ...row]));
          w4.addConditionalFormatting({ ref: 'B2:Y8', rules: [{ type: 'colorScale', cfvo: [{ type: 'min' }, { type: 'max' }], color: [{ argb: 'FFFFFFFF' }, { argb: 'FF0F7A5C' }] }] });
          w4.addRow([]);
          const hh = w4.addRow(['חלק יום', 'שיחות', 'מספרים שזה החלק העיקרי שלהם']); hh.font = { bold: true };
          res.buckets.forEach(b => w4.addRow([b.name, b.calls, b.mainFor]));
      
          const w5 = wb.addWorksheet('לפי חודש', { views: [{ rightToLeft: true, state: 'frozen', ySplit: 1 }] });
          w5.columns = [['חודש', 12], ['שיחות', 12], ['מספרים פעילים', 14], ['מספרים חדשים (הופיעו לראשונה)', 22]].map(c => ({ header: c[0], width: c[1] }));
          hdr(w5);
          res.months.forEach(m => w5.addRow([m.month, m.calls, m.active, m.fresh]));
          return wb;
        }
      
        function toCSV(res) {
          const esc = v => { v = v instanceof Date ? v.toISOString().slice(0, 16).replace('T', ' ') : String(v); return /[",\n]/.test(v) ? '"' + v.replace(/"/g, '""') + '"' : v; };
          const lines = [MAIN_COLS.map(c => esc(c[0])).join(',')];
          for (const r of res.rows) { const row = mainRow(r); row[0] = '\t' + row[0]; lines.push(row.map(esc).join(',')); }
          return '\uFEFF' + lines.join('\r\n');
        }
      
        return { isAnon, normPhone, phoneInfo, parseLogText, parseCityMap, newAgg, addRecords, finalize, buildWorkbook, toCSV, mkey, BUCKETS };
      })();
      if (typeof module !== 'undefined') module.exports = T;
      </script>
      
      <script>
      (() => {
      if (typeof document === 'undefined') return;
      const $ = id => document.getElementById(id);
      const BASE = 'https://www.call2all.co.il/ym/api/';
      let mode = 'pass', token = null, result = null, cityMap = new Map();
      const pad = n => String(n).padStart(2, '0');
      const fmtNum = n => Number(n).toLocaleString('he-IL');
      const fmtD = t => { const d = new Date(t); return pad(d.getDate()) + '/' + pad(d.getMonth() + 1) + '/' + d.getFullYear(); };
      function show(el, msg, kind) { el.hidden = !msg; el.className = 'status' + (kind ? ' ' + kind : ''); el.textContent = msg || ''; }
      const tick = () => new Promise(r => setTimeout(r, 0));
      
      function netError(e) { return e instanceof TypeError ? new Error('הדפדפן לא הצליח לפנות לשרת של ימות המשיח (אין אינטרנט או שהבקשה נחסמה). אפשר להעלות קבצי לוג ידנית.') : e; }
      async function api(method, params = {}) {
        let res; try { res = await fetch(BASE + method + '?' + new URLSearchParams({ token, ...params })); } catch (e) { throw netError(e); }
        const txt = await res.text(); let j; try { j = JSON.parse(txt); } catch { throw new Error('תשובה לא צפויה מהשרת (' + res.status + ').'); }
        if (j.responseStatus && j.responseStatus !== 'OK') throw new Error(j.message || ('השרת החזיר: ' + j.responseStatus));
        return j;
      }
      function decode(buf) {
        try { return new TextDecoder('utf-8', { fatal: true }).decode(buf); }
        catch { try { return new TextDecoder('windows-1255').decode(buf); } catch { return new TextDecoder().decode(buf); } }
      }
      async function apiText(method, params = {}) {
        let res; try { res = await fetch(BASE + method + '?' + new URLSearchParams({ token, ...params })); } catch (e) { throw netError(e); }
        if (res.status === 404) throw new Error('הקובץ לא נמצא במערכת.');
        const txt = decode(await res.arrayBuffer());
        if (/^\s*\{/.test(txt)) { try { const j = JSON.parse(txt); if (j.responseStatus && j.responseStatus !== 'OK') throw new Error(j.message || j.responseStatus); } catch (e) { if (!(e instanceof SyntaxError)) throw e; } }
        return txt;
      }
      
      function setMode(m) { mode = m; $('m-pass').setAttribute('aria-pressed', m === 'pass'); $('m-token').setAttribute('aria-pressed', m === 'token'); $('f-num').hidden = $('f-pass').hidden = m !== 'pass'; $('f-token').hidden = m !== 'token'; }
      $('m-pass').onclick = () => setMode('pass'); $('m-token').onclick = () => setMode('token');
      
      $('conn').addEventListener('submit', async e => {
        e.preventDefault(); const st = $('conn-status');
        if (mode === 'pass') { const n = $('num').value.trim(), p = $('pass').value.trim(); if (!n || !p) return show(st, 'הקלד מספר מערכת וסיסמה.', 'err'); token = n + ':' + p; }
        else { const t = $('token').value.trim(); if (!t) return show(st, 'הדבק טוקן או מפתח API.', 'err'); token = t; }
        $('btn-conn').disabled = true; show(st, 'מתחבר…');
        try { const s = await api('GetSession'); show(st, 'מחובר' + (s.username ? ' למערכת ' + s.username : '') + (s.name ? ' · ' + s.name : '')); $('btn-pull').disabled = false; }
        catch (err) { token = null; $('btn-pull').disabled = true; show(st, 'ההתחברות נכשלה: ' + err.message, 'err'); }
        finally { $('btn-conn').disabled = false; }
      });
      
      $('mapfile').onchange = async e => {
        const f = e.target.files[0]; if (!f) return;
        cityMap = T.parseCityMap(decode(await f.arrayBuffer()));
        $('map-status').textContent = cityMap.size ? 'נטענו ' + fmtNum(cityMap.size) + ' מספרים מקובץ ההתאמה.' : 'לא זוהו שורות. ודא שיש עמודת "טלפון" ועמודת "עיר".';
        if (result) { /* ייושם בשליפה הבאה */ $('map-status').textContent += ' יחול בשליפה הבאה.'; }
      };
      
      function finish(agg) {
        result = T.finalize(agg, Date.now(), cityMap);
        const s = result.summary;
        const k = [['מספרים שונים', s.numbers], ['שיחות', s.calls], ['פעילים ב-30 יום', s.active30], ['התקשרו פעם אחת', s.onceOnly], ['שיחות חסויות', s.anonCalls]];
        $('kpis').innerHTML = ''; k.forEach(([a, b]) => { const d = document.createElement('div'); d.className = 'kpi'; d.innerHTML = '<span class="k"></span><span class="v"></span>'; d.firstChild.textContent = a; d.lastChild.textContent = fmtNum(b); $('kpis').appendChild(d); });
        const tb = $('prev'); tb.innerHTML = '';
        for (const r of result.rows.slice(0, 100)) {
          const tr = document.createElement('tr');
          [[r.phone, 'num'], [r.region], [r.city], [fmtD(r.first), 'num'], [fmtD(r.last), 'num'], [fmtNum(r.tenureDays), 'num'], [fmtNum(r.calls), 'num'], [r.mainBucket], [r.status]].forEach(([t, c]) => { const td = document.createElement('td'); td.textContent = t; if (c) td.className = c; tr.appendChild(td); });
          tb.appendChild(tr);
        }
        $('res').hidden = false;
      }
      
      $('btn-pull').onclick = async () => {
        const st = $('pull-status'), pg = $('prog'); $('btn-pull').disabled = true; pg.hidden = false; pg.value = 0;
        try {
          show(st, 'טוען את רשימת הקבצים בתיקיית Log…');
          const d = await api('GetIVR2Dir', { path: 'ivr2:/Log' });
          let months = (d.files || []).map(f => f.name || f.fileName || '').map(n => (n.match(/^LogFolderEnterExit-(\d{4}-\d{2})/) || [])[1]).filter(Boolean);
          months = [...new Set(months)].sort();
          const a = $('from').value, b = $('to').value;
          if (a) months = months.filter(m => m >= a); if (b) months = months.filter(m => m <= b);
          if (!months.length) throw new Error('לא נמצאו קבצי LogFolderEnterExit בתיקיית Log (בטווח שנבחר).');
          const agg = T.newAgg(), failed = [];
          pg.max = months.length;
          for (let i = 0; i < months.length; i++) {
            show(st, 'מוריד ומעבד ' + months[i] + ' (' + (i + 1) + ' מתוך ' + months.length + ') · עד עכשיו ' + fmtNum(agg.phones.size) + ' מספרים');
            try { T.addRecords(agg, T.parseLogText(await apiText('DownloadFile', { path: 'ivr2:/Log/LogFolderEnterExit-' + months[i] + '.ymgr' }))); }
            catch (err) { failed.push(months[i] + ' (' + err.message + ')'); }
            pg.value = i + 1; await tick();
          }
          if (!agg.phones.size) throw new Error('לא נקראו נתונים. ' + (failed.length ? 'כשלו: ' + failed.join('; ') : ''));
          finish(agg);
          show(st, 'הסתיים: ' + fmtNum(result.summary.numbers) + ' מספרים מתוך ' + months.length + ' חודשים.' + (failed.length ? ' לא נטענו: ' + failed.join('; ') : ''), failed.length ? 'warn' : '');
        } catch (err) { show(st, err.message, 'err'); }
        finally { $('btn-pull').disabled = !token; pg.hidden = true; }
      };
      
      $('logfiles').onchange = async e => {
        const st = $('pull-status'), files = [...e.target.files].sort((a, b) => a.name.localeCompare(b.name));
        if (!files.length) return;
        const agg = T.newAgg();
        for (const f of files) { show(st, 'מעבד ' + f.name + '…'); T.addRecords(agg, T.parseLogText(decode(await f.arrayBuffer()))); await tick(); }
        if (!agg.phones.size) return show(st, 'לא זוהו שורות לוג בקבצים.', 'err');
        finish(agg); show(st, 'הסתיים: ' + fmtNum(result.summary.numbers) + ' מספרים מ-' + files.length + ' קבצים.');
      };
      
      function save(blob, name) { const a = document.createElement('a'); a.href = URL.createObjectURL(blob); a.download = name; document.body.appendChild(a); a.click(); a.remove(); setTimeout(() => URL.revokeObjectURL(a.href), 4000); }
      const stamp = () => { const d = new Date(); return d.getFullYear() + pad(d.getMonth() + 1) + pad(d.getDate()); };
      $('btn-xlsx').onclick = async () => {
        if (!result) return;
        if (typeof ExcelJS === 'undefined') return show($('xlsx-warn'), 'ספריית האקסל לא נטענה (כנראה חסומה בסינון או שאין אינטרנט). אפשר להוריד CSV, שנפתח באקסל.', 'warn');
        $('btn-xlsx').disabled = true; show($('xlsx-warn'), 'בונה קובץ אקסל…');
        try { await tick(); const buf = await T.buildWorkbook(ExcelJS, result).xlsx.writeBuffer(); save(new Blob([buf], { type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' }), 'phone-book-' + stamp() + '.xlsx'); show($('xlsx-warn'), ''); }
        catch (err) { show($('xlsx-warn'), 'בניית האקסל נכשלה: ' + err.message + '. נסה CSV.', 'err'); }
        finally { $('btn-xlsx').disabled = false; }
      };
      $('btn-csv').onclick = () => { if (result) save(new Blob([T.toCSV(result)], { type: 'text/csv;charset=utf-8' }), 'phone-book-' + stamp() + '.csv'); };
      })();
      </script>
      </body>
      </html>
      
      
      פורסם בטיפים עצות והדגמות מהמשתמשים
      י
      ישראל10
    • RE: ממשק HTML לבדיקת כמות מאזינים בו זמנית (ערוצים)

      @מסובך-מאוד לא מצליח להעלות...

      פורסם בטיפים עצות והדגמות מהמשתמשים
      י
      ישראל10
    • RE: ממשק HTML לבדיקת כמות מאזינים בו זמנית (ערוצים)

      @איל-משולש בניתי קובץ נחמד לקבלת נתונים עם אפשרות להוריד לאקסל.
      yemot-phone-book.html

      פורסם בטיפים עצות והדגמות מהמשתמשים
      י
      ישראל10
    • RE: ממשק HTML לבדיקת כמות מאזינים בו זמנית (ערוצים)

      @איל-משולש שלך יותר טוב..

      פורסם בטיפים עצות והדגמות מהמשתמשים
      י
      ישראל10
    • RE: דרמה!! מישהו שמע על זה????

      @אז-נדברו כתב:

      @מוטי-לוין נבחנת כעת אפשרות של תמחור של 0.5 יחידות על כל דקת שיחה מעבר למגבלת ערוצים, וכך מי שירצה יוכל לאפשר חיוג מעבר למכסה.

      אני חושב שזה רעיון מושלם!!!
      לפי נתונים של החודשים האחרונים, יספיק לי 20 ערוצים, אבל יש בערך 7 או 10 פעמים בחודש שיש בערך 25 ערוצים, בסך הכול בחודש האחרון היו 3 דקות שעקפתי את ה20 ערוצים, אני חושב שזה יספק פיתרון טוב ומושלם!!!

      פורסם בשאלות ועזרה הדדית
      י
      ישראל10
    • RE: ממשק HTML לבדיקת כמות מאזינים בו זמנית (ערוצים)

      @איל-משולש בסוף זה עבד...
      כמוך, רק שלך יותר תקין.
      1ceee909-fbdd-40dc-a452-48cf54ba4091-image.jpeg

      פורסם בטיפים עצות והדגמות מהמשתמשים
      י
      ישראל10
    • RE: ממשק HTML לבדיקת כמות מאזינים בו זמנית (ערוצים)

      @איל-משולש אני בכלל לא בטוח ששלך לא עובד...
      אני בודק את זה..
      עריכה.
      יש מחלוקת עצובה ביניכם...
      שלך טוען שהגעתי ל108 ערוצים, בעוד שהוא טוען שהגעתי ל39 ערוצים בלבד...
      ואני נוטה להאמין לשלך, כי הוצאתי אז צינטוק ל2000 איש ביחד..., לכאורה חזרו מיד לפחות 100
      אבל אני רואה שהוא לא הצליח לשאוב את כל הזמנים...
      אני בודק רק את הזמנים המועדים לפורענות...

      פורסם בטיפים עצות והדגמות מהמשתמשים
      י
      ישראל10
    • RE: ממשק HTML לבדיקת כמות מאזינים בו זמנית (ערוצים)

      @איל-משולש ואיפה אני רואה את זה

      פורסם בטיפים עצות והדגמות מהמשתמשים
      י
      ישראל10
    • RE: ממשק HTML לבדיקת כמות מאזינים בו זמנית (ערוצים)

      @איל-משולש זה הגיוני שיש לי מעל 20 אלף דקות ואני לא עובר את ה12 חיבורים ביחד?
      עריכה, בחרתי בכל החודשים וזה הביא לי נתונים אחרים...
      19b6e6ae-15f1-4986-b3cc-494131aabcb2-image.jpeg

      פורסם בטיפים עצות והדגמות מהמשתמשים
      י
      ישראל10
    • RE: דרמה!! מישהו שמע על זה????

      @אז-נדברו ובאופציה שהמערכת מחייגת ללקוח, [לא קמפיין קולי] זה נחשב כערוץ?

      פורסם בשאלות ועזרה הדדית
      י
      ישראל10