Torn Quick Deposit

Quick Deposit cash to Ghost Trade / Company Vault / Faction Vault

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

You will need to install an extension such as Tampermonkey to install this script.

Tendrás que instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Tendrás que instalar una extensión como Tampermonkey antes de poder instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Tendrás que instalar una extensión como Stylus antes de poder instalar este script.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

Para poder instalar esto tendrás que instalar primero una extensión de estilos de usuario.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         Torn Quick Deposit
// @namespace    http://tampermonkey.net/
// @version      1.3.6
// @description  Quick Deposit cash to Ghost Trade / Company Vault / Faction Vault
// @author       e7cf09 [3441977]
// @icon         https://editor.torn.com/cd385b6f-7625-47bf-88d4-911ee9661b52-3441977.png
// @match        https://www.torn.com/*
// @run-at       document-start
// @grant        none
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // CONFIG & STATE
    // USAGE: Set PANIC_THRESHOLD for auto-triggers. Map physical keys in KEYS object.
    // EXAMPLES: Empty: [], Single: ["KeyA"], Multiple: ["ControlLeft", "KeyA"]
    const CONFIG = {
        PANIC_THRESHOLD: 20000000, // Panic Threshold: Only triggers if balance exceeds this
        STRICT_GHOST_MODE: true, // Relaxed matching for Ghost trades (if false, any trade found is used)
        PRIORITY: ["GHOST", "COMPANY", "FACTION"], // Order of preference for auto-deposit
        KEYS: {
            FACTION: [],
            GHOST: [],
            COMPANY: [],
            RESET: [],
            PANIC: ["KeyP"],
            EXECUTE: [] // Auto-deposit / Panic Execute
        },
        DEAD_SIGNALS: ["no trade was found", "trade has been accepted", "declined", "cancelled", "locked"]
    };

    const STATE = {
        balance: 0,
        panic: localStorage.getItem('torn_tactical_panic_enabled') !== 'false',
        ghostID: localStorage.getItem('torn_tactical_ghost_id'),
        locks: { panic: false, sending: false, jumping: false, dead: false },
        els: { overlay: null, btn: null }
    };

    // UTILS
    const qs = (s, p=document) => p.querySelector(s);
    const qsa = (s, p=document) => p.querySelectorAll(s);
    const fmt = (n) => "$" + parseInt(n).toLocaleString('en-US');
    const setStyle = (el, css) => Object.assign(el.style, css);

    // NETWORK INTERCEPT
    const intercept = (proto, method, handler) => {
        const orig = proto[method];
        proto[method] = function(...args) {
            handler(this, args);
            return orig.apply(this, args);
        };
    };

    intercept(XMLHttpRequest.prototype, 'open', (xhr, args) => xhr._url = args[1]);
    intercept(XMLHttpRequest.prototype, 'send', (xhr) => {
        xhr.addEventListener('load', () => {
            if (xhr._url?.includes('trade.php')) checkDeadTrade(xhr.responseText, xhr._url);
        });
    });

    const origFetch = window.fetch;
    window.fetch = async (...args) => {
        const res = await origFetch(...args);
        const url = args[0]?.toString() || '';

        // Only intercept specific JSON endpoints to avoid cloning heavy assets (images, scripts)
        if (url.match(/sidebar|user/) && res.headers.get('content-type')?.includes('json')) {
            try {
                // If on Holdem, we STILL parse sidebar updates because they contain real user money
                // The previous blockage was too aggressive. The fetch response for sidebar IS safe.
                res.clone().json().then(d => updateBalance(d?.user?.money || d?.sidebarData?.user?.money)).catch(()=>{});
            } catch (e) {}
        }
        return res;
    };

    // WEBSOCKET INTERCEPT
    const OrigWS = window.WebSocket;
    window.WebSocket = function(url, protocols) {
        const ws = new OrigWS(url, protocols);
        ws.addEventListener('message', e => {
            if (typeof e.data !== 'string') return;

            // In Holdem page, only filter out game channels, but allow user updates (sidebar)
            if (window.location.href.includes('sid=holdem')) {
                try {
                    const data = JSON.parse(e.data);
                    // Filter out poker game channels
                    if (data.push && data.push.channel && data.push.channel.includes('holdem')) return;
                } catch (err) {}
            }

            if (e.data.includes('attack-effects')) triggerPanic();
            const m = e.data.match(/"money"\s*:\s*(\d+)/);
            if (m) updateBalance(m[1]);
        });
        return ws;
    };
    window.WebSocket.prototype = OrigWS.prototype;

    // LOGIC
    function checkDeadTrade(text, url) {
        if (!text || text.length < 20) return;
        if (CONFIG.DEAD_SIGNALS.some(s => text.toLowerCase().includes(s))) {
            let id = null;
            if (url && url.includes('ID=')) {
                const match = url.match(/ID=(\d+)/);
                if (match) id = match[1];
            } else {
                const params = new URLSearchParams(window.location.hash.substring(1) || window.location.search);
                id = params.get('ID');
            }

            if (STATE.ghostID && id === STATE.ghostID) {
                localStorage.removeItem('torn_tactical_ghost_id');
                STATE.ghostID = null;
                injectBtn();
            }
        }
    }

    function getStatus() {
        const icons = qsa('ul[class*="status-icons"] > li');
        if (!icons.length) return { faction: true, ghost: true, company: false, reason: "LOADING" }; // Aggressive default

        let s = { faction: true, ghost: true, company: false, reason: "" };
        let isHosp = false, isTravel = false;

        icons.forEach(li => {
            if (li.className.match(/icon1[56]/)) isHosp = true;
            if (li.className.includes('icon71')) isTravel = true;
            if (li.className.includes('icon73')) s.company = true;
        });

        if (isHosp) { s.faction = s.company = false; s.reason = "HOSP/JAIL"; }
        else if (isTravel) { s.faction = s.ghost = s.company = false; s.reason = "TRAVEL"; }

        // Special check for Faction: Ensure we are in a faction
        const sidebarFaction = qs('a[href^="/factions.php"]');
        if (!sidebarFaction) s.faction = false;

        return s;
    }

    function updateBalance(val) {
        if (!val) return;

        const num = parseInt(typeof val === 'object' ? val.value : val);
        if (isNaN(num)) return;

        STATE.balance = num;
        if (STATE.balance <= 0) {
            STATE.locks.sending = false;
            dismissPanic();
        } else if (STATE.balance >= CONFIG.PANIC_THRESHOLD && STATE.panic) {
            const s = getStatus();
            if (STATE.ghostID ? s.ghost : s.faction) triggerPanic();
        } else if (STATE.locks.panic) {
            dismissPanic();
        }
        if (STATE.locks.panic) updateOverlay();
    }

    function triggerPanic() {
        if (!STATE.panic || STATE.balance < CONFIG.PANIC_THRESHOLD) return;
        const s = getStatus();
        if (s.reason === 'LOADING') return; // Wait for icons to load
        if (!(STATE.ghostID && s.ghost) && !s.company && !s.faction) return;

        STATE.locks.panic = true;
        updateOverlay();
    }

    function dismissPanic() {
        STATE.locks.panic = false;
        STATE.locks.sending = false;
        if (STATE.els.overlay) STATE.els.overlay.style.display = 'none';
    }

    async function executeDeposit(mode = 'auto') {
        // 1. Handle Confirmation Boxes immediately
        const box = Array.from(qsa('.cash-confirm')).find(b => b.offsetParent && b.style.display !== 'none');
        if (box) {
            if (box.querySelector('.yes')) {
                if (STATE.els.overlay) STATE.els.overlay.innerHTML = "DEPOSITING...";
                box.querySelector('.yes').click();
                STATE.locks.sending = false;
                return;
            }
        }

        // Reset sending lock if confirmation box is gone (User clicked No/Cancel)
        if (!box && STATE.locks.sending) {
            // Check if we are stuck in sending state without a box
            // This happens if user clicked No, or closed the modal
            STATE.locks.sending = false;
        }

        if (STATE.locks.sending) return;
        const status = getStatus();

        // Determine Target Mode
        let target = mode;
        if (mode === 'auto') {
            for (const type of CONFIG.PRIORITY) {
                if (type === 'GHOST' && STATE.ghostID && status.ghost) { target = 'ghost'; break; }
                if (type === 'COMPANY' && status.company) { target = 'company'; break; }
                if (type === 'FACTION' && status.faction) { target = 'faction'; break; }
            }
            if (!target) return;
        }

        // Validate Target with strict mode checks
        if (target === 'ghost') {
            // Strict check: Must have Ghost ID AND allow ghost status
            if (!STATE.ghostID || !status.ghost) {
                 if (mode === 'ghost') return; // Explicit request fails
                 // Fallback for auto: Try Company -> Faction
                 target = status.company ? 'company' : (status.faction ? 'faction' : null);
            }
        }
        if (target === 'company' && !status.company) {
            if (mode !== 'auto') return; // Strict fail for manual mode
            target = status.faction ? 'faction' : null;
        }
        if (target === 'faction' && !status.faction) {
             if (mode !== 'auto') return;
             target = null;
        }
        if (!target) return;

        // EXECUTION
        const setVal = (input, val) => {
            // React Hack: Bypass internal value tracking to ensure state update
            const setter = Object.getOwnPropertyDescriptor(window.HTMLInputElement.prototype, 'value').set;
            if (setter) {
                setter.call(input, val);
            } else {
                input.value = val;
            }

            input.dispatchEvent(new Event('input', { bubbles: true }));
            input.dispatchEvent(new Event('change', { bubbles: true }));
            input.dispatchEvent(new Event('blur', { bubbles: true }));
        };

        const jump = (url, msg) => {
            if (STATE.locks.jumping) return;
            STATE.locks.jumping = true;
            if (STATE.els.overlay) STATE.els.overlay.innerHTML = msg;
            setTimeout(() => STATE.locks.jumping = false, 1500);
            window.location.href = url;
        };

        if (target === 'ghost') {
            const url = window.location.href;
            // Relaxed check: Just need to be on trade.php and have the correct ID
            // We'll let the element check determine if we are on the "add money" view
            const onPageWithID = url.includes('trade.php') && url.includes(STATE.ghostID);

            // Check if the specific "Add Money" input exists
            const input = qs('.input-money[type="text"]');

            if (!onPageWithID || !input) {
                return jump(`https://www.torn.com/trade.php#step=addmoney&ID=${STATE.ghostID}`, "JUMPING<br>TO GHOST");
            }

            STATE.locks.sending = true;
            if (STATE.els.overlay) STATE.els.overlay.innerHTML = "DEPOSITING<br>TO GHOST";
            setVal(input, input.getAttribute('data-money') || STATE.balance);

            const btn = input.form?.querySelector('input[type="submit"], button[type="submit"]') || qs('input[type="submit"][value="Change"], button[type="submit"][value="Change"]');
            if (btn) {
                btn.disabled = false;
                btn.classList.remove('disabled');
                btn.click();
                STATE.locks.jumping = false;
            } else STATE.locks.sending = false;

        } else if (target === 'company') {
            const url = window.location.href;
            const onPage = url.includes('companies.php') && url.includes('option=funds');

            // Precise selector for Deposit Input (vs Withdraw)
            const input = qs('input[aria-labelledby="deposit-label"][type="text"]');

            if (!input) {
                if (!onPage) return jump(`https://www.torn.com/companies.php?step=your&type=1#/option=funds`, "JUMPING<br>TO COMPANY");
                return;
            }

            STATE.locks.sending = true;
            if (STATE.els.overlay) STATE.els.overlay.innerHTML = "DEPOSITING<br>TO COMPANY";
            setVal(input, input.getAttribute('data-money') || STATE.balance);

            const container = input.closest('.funds-cont');
            const btn = container ? container.querySelector('.deposit.btn-wrap button') : null;

            if (btn) {
                btn.disabled = false;
                btn.click();
            } else STATE.locks.sending = false;

        } else { // Faction
            const form = qs('.give-money-form') || qs('.input-money')?.closest('form');
            const onPage = window.location.href.includes('factions.php') && window.location.href.includes('tab=armoury');

            if (!form) {
                if (!onPage) return jump(`https://www.torn.com/factions.php?step=your&type=1#/tab=armoury`, "JUMPING<br>TO FACTION");
                qs('a[href*="tab=armoury"]')?.click();
                return;
            }

            const input = form.querySelector('.input-money');
            if (!input) return;

            STATE.locks.sending = true;
            if (STATE.els.overlay) STATE.els.overlay.innerHTML = "DEPOSITING<br>TO FACTION";

            let amt = input.getAttribute('data-money');
            if (!amt) {
                const txt = form.querySelector('.i-have')?.innerText.replace(/[$,]/g, '');
                if (txt && !isNaN(txt)) amt = txt;
            }
            setVal(input, amt || STATE.balance);

            const btn = form.querySelector('button.torn-btn');
            if (btn) {
                btn.disabled = false;
                btn.click();
            } else STATE.locks.sending = false;
        }
    }

    // UI COMPONENTS
    function showToast(html) {
        const t = document.createElement('div');
        t.innerHTML = `<div style="font-size:11px;color:#aaa;margin-bottom:4px;text-transform:uppercase;">Quick Deposit</div>${html}`;
        setStyle(t, {
            position: 'fixed', top: '15%', left: '50%', transform: 'translate(-50%, -50%)',
            zIndex: 2147483647, background: 'rgba(0,0,0,0.85)', color: 'white',
            padding: '12px 24px', borderRadius: '8px', pointerEvents: 'none',
            opacity: 0, transition: 'opacity 0.3s', textAlign: 'center', border: '1px solid #ffffff33'
        });
        document.body.appendChild(t);
        requestAnimationFrame(() => t.style.opacity = '1');
        setTimeout(() => { t.style.opacity = '0'; setTimeout(() => t.remove(), 300); }, 2000);
    }

    function updateOverlay() {
        if (!STATE.locks.panic || STATE.balance <= 0) return dismissPanic();

        if (!STATE.els.overlay) {
            const d = document.createElement('div');
            d.id = 'torn-panic-overlay';
            let css = `position: fixed; z-index: 2147483647; background: rgba(255, 0, 0, 0.9); color: white;
                font-family: 'Arial Black', sans-serif; font-size: 14px; text-align: center;
                padding: 10px 20px; border-radius: 30px; border: 3px solid white;
                box-shadow: 0 0 20px red; cursor: pointer; white-space: nowrap; user-select: none;`;

            // Default to off-screen, will be moved by mousemove
            css += `top: -999px; left: -999px; transform: translate(-50%, -50%);`;

            d.style.cssText = css;
            d.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); executeDeposit('auto'); });
            document.addEventListener('mousemove', e => {
                if (STATE.locks.panic) {
                    d.style.left = e.clientX + 'px';
                    d.style.top = e.clientY + 'px';
                }
            });
            document.body.appendChild(d);
            STATE.els.overlay = d;
        }

        STATE.els.overlay.style.display = 'block';
        if (STATE.locks.sending || STATE.locks.jumping) return;

        // Determine Text
        let txt = "JUMP TO<br>FACTION";
        if (qs('.cash-confirm')) {
            txt = "CONFIRM<br>DEPOSIT";
        } else {
            const s = getStatus();
            let target = null;

            // Determine active target based on priority
            for (const type of CONFIG.PRIORITY) {
                if (type === 'GHOST' && STATE.ghostID && s.ghost) { target = 'GHOST'; break; }
                if (type === 'COMPANY' && s.company) { target = 'COMPANY'; break; }
                if (type === 'FACTION' && s.faction) { target = 'FACTION'; break; }
            }

            if (target === 'GHOST') {
                // Ghost Logic
                const hashParams = new URLSearchParams(window.location.hash.substring(1));
                const searchParams = new URLSearchParams(window.location.search);
                const currentStep = hashParams.get('step') || searchParams.get('step');
                const currentID = hashParams.get('ID') || searchParams.get('ID');

                const onGhostPage = window.location.href.includes('trade.php') &&
                                    currentStep === 'addmoney' &&
                                    currentID === STATE.ghostID;

                txt = onGhostPage ? `DEPOSIT<br>${fmt(STATE.balance)}<br><span style='font-size:10px'>GHOST</span>` : "JUMP TO<br>GHOST";

            } else if (target === 'COMPANY') {
                // Company Logic
                const onCompanyPage = window.location.href.includes('companies.php') && window.location.href.includes('option=funds');
                const container = qs('.funds-cont');
                // We are "on page" if URL matches AND the funds container is present (meaning loaded)
                // OR if URL matches and we are just waiting for load (to prevent flickering JUMP TO)
                const ready = onCompanyPage && (container || document.readyState === 'loading');

                txt = ready ? `DEPOSIT<br>${fmt(STATE.balance)}<br><span style='font-size:10px'>COMPANY</span>` : "JUMP TO<br>COMPANY";

            } else {
                // Faction Logic (Default)
                const current = window.location.href;
                const onFactionPage = current.includes('factions.php') && current.includes('step=your') && current.includes('type=1') && current.includes('tab=armoury');
                const form = qs('.give-money-form');

                // Show DEPOSIT if form exists OR if we are on the correct URL (even if form hasn't loaded yet)
                const ready = form || onFactionPage;

                txt = ready ? `DEPOSIT<br>${fmt(STATE.balance)}` : "JUMP TO<br>FACTION";
            }
        }

        if (STATE.els.overlay.innerHTML !== txt) STATE.els.overlay.innerHTML = txt;
    }

    function injectBtn() {
        const moneyEl = document.getElementById('user-money');
        if (!moneyEl) return;

        if (!STATE.els.btn) {
            const b = document.createElement('a');
            b.id = 'torn-tactical-deposit';
            b.href = '#';
            b.style.marginLeft = '10px';
            b.style.cursor = 'pointer';

            // Hardcoded style to match [use] button in sidebar
            // Based on user feedback: class="use___wM1PI"
            b.className = 'use___wM1PI';

            // Fallback inline styles only if class fails to apply styles
            // We set marginLeft because original element might have margin defined in CSS
            b.style.marginLeft = '10px';

            b.addEventListener('click', (e) => { e.preventDefault(); executeDeposit('auto'); });
            STATE.els.btn = b;
        }

        if (moneyEl.parentNode && moneyEl.nextSibling !== STATE.els.btn) {
            moneyEl.parentNode.insertBefore(STATE.els.btn, moneyEl.nextSibling);
        }

        const s = getStatus();
        let txt = '[deposit]', title = 'Vault Deposit';

        // Determine active target based on priority
        for (const type of CONFIG.PRIORITY) {
            if (type === 'GHOST' && STATE.ghostID) {
                txt = '[ghost]';
                title = `Ghost ID: ${STATE.ghostID}`;
                break;
            }
            if (type === 'COMPANY' && s.company) {
                txt = '[deposit]';
                title = "Company Vault";
                break;
            }
            if (type === 'FACTION' && s.faction) {
                txt = '[deposit]';
                title = "Faction Vault";
                break;
            }
        }

        if (STATE.els.btn.innerText !== txt) STATE.els.btn.innerText = txt;
        if (STATE.els.btn.title !== title) STATE.els.btn.title = title;
    }

    // EVENT LISTENERS
    window.addEventListener('keydown', e => {
        if (!e.isTrusted || e.target.matches('input, textarea') || e.target.isContentEditable) return;
        const k = e.code;

        // Helper to check if key matches any in the list
        const isKey = (type) => CONFIG.KEYS[type] && CONFIG.KEYS[type].includes(k);

        // Prevent default if it's any of our keys
        if (Object.values(CONFIG.KEYS).flat().includes(k)) e.preventDefault();

        if (isKey('FACTION')) executeDeposit('faction');
        if (isKey('GHOST') && STATE.ghostID) executeDeposit('ghost');
        if (isKey('COMPANY')) executeDeposit('company');
        if (isKey('EXECUTE')) executeDeposit('auto');
        if (isKey('RESET')) {
            localStorage.removeItem('torn_tactical_ghost_id');
            STATE.ghostID = null;
            injectBtn();
            showToast("GHOST ID CLEARED");
        }
        if (isKey('PANIC')) {
            STATE.panic = !STATE.panic;
            localStorage.setItem('torn_tactical_panic_enabled', STATE.panic);
            showToast(`PANIC MODE <span style="color:${STATE.panic?'#4dff4d':'#ff4d4d'}">${STATE.panic?'ON':'OFF'}</span>`);
            if (STATE.panic) updateBalance(STATE.balance); // Trigger check
            else dismissPanic();
        }
    });

    window.addEventListener('hashchange', () => {
        if (STATE.locks.jumping && STATE.ghostID && window.location.href.includes(STATE.ghostID)) STATE.locks.jumping = false;
        if (STATE.locks.panic) updateOverlay();
    });

    // INIT
    const scanTrades = () => {
        if (!window.location.href.includes('trade.php')) return;

        // Handle both Hash (Vue/React router) and Search (Legacy) params
        const params = new URLSearchParams(window.location.hash.substring(1) || window.location.search);
        const currentID = params.get('ID');

        // Check for dead signals on page load
        if (qs('.info-msg, .error-msg')?.innerText.match(new RegExp(CONFIG.DEAD_SIGNALS.join('|'), 'i'))) {
            if (STATE.ghostID && currentID === STATE.ghostID) {
                STATE.ghostID = null; localStorage.removeItem('torn_tactical_ghost_id'); injectBtn(); return;
            }
        }

        // Capture from Log (Priority: Check chat logs on Trade View page)
        if (currentID) {
            const logs = qsa('ul.log .msg');
            let isGhost = false;

            if (!CONFIG.STRICT_GHOST_MODE) {
                // If not strict, ANY trade we visit is considered valid
                isGhost = true;
            } else {
                isGhost = Array.from(logs).some(msg => {
                    const clone = msg.cloneNode(true);
                    clone.querySelector('a')?.remove(); // Remove username
                    return clone.innerText.toLowerCase().includes('ghost');
                });
            }

            if (isGhost && !STATE.ghostID) {
                STATE.ghostID = currentID;
                localStorage.setItem('torn_tactical_ghost_id', currentID);
                injectBtn();
            }
        }

        // Capture from List (Only if not locked, and only if we are not on a specific trade page)
        if (!currentID && !STATE.ghostID) {
            qsa('ul.trade-list-container > li').forEach(li => {
                // Check content excluding username
                const clone = li.cloneNode(true);
                clone.querySelector('.user.name')?.remove();

                if (!CONFIG.STRICT_GHOST_MODE || clone.innerText.toLowerCase().includes('ghost')) {
                    const mid = li.querySelector('a.btn-wrap')?.href.match(/ID=(\d+)/);
                    if (mid) { STATE.ghostID = mid[1]; localStorage.setItem('torn_tactical_ghost_id', mid[1]); injectBtn(); }
                }
            });
        }
    };

    // INIT
    let mutationTimeout = null;
    const observerCallback = (mutations) => {
        let ignore = true;
        for (const m of mutations) {
            // Use nodeType check to ensure we only check Element properties
            const isElement = m.target.nodeType === 1;
            const targetId = isElement ? m.target.id : '';

            if (!targetId?.includes('torn-') &&
                (!isElement || !m.target.closest?.('#torn-tactical-deposit')) &&
                (!isElement || !m.target.closest?.('#torn-panic-overlay'))) {
                ignore = false;
                break;
            }
        }
        if (ignore) return;

        if (mutationTimeout) clearTimeout(mutationTimeout);
        mutationTimeout = setTimeout(() => {
            injectBtn();
            scanTrades();
        }, 50); // Debounce 50ms
    };

    let init = false;
    const start = () => {
        if (init) return;
        init = true;

        // Initial Balance Check from DOM
        const moneyEl = document.getElementById('user-money');
        if (moneyEl) {
            const val = moneyEl.getAttribute('data-money') || moneyEl.innerText.replace(/[^\d]/g, '');
            if (val) updateBalance(val);
        }

        // Observers
        new MutationObserver(observerCallback).observe(document, { childList: true, subtree: true });

        // Early Init
        if (moneyEl) injectBtn();
    };

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', start);
    } else start();

})();