HWM Work

try to take over the world!

// ==UserScript==
// @name         HWM Work
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        https://www.heroeswm.ru/pl_info.php?id=*/
// @grant        none
// ==/UserScript==

(function () {
    var myBot = (() => {
        var globalVars = {
            charParams: { id: null },
            serverUrl: 'http://localhost:3000',
            hwmUrl: 'https://www.heroeswm.ru',
            sellResUrl: 'sell_res.php',
            firstOpenProdUrl: '',
            workParams: {},
            statuses: {
                work: false,
                sellElements: false
            },
            resources: {
                'Золото':            { cost: 1,     minCount: 0, factoryTitle: null },
                'Древесина':         { cost: 180,   minCount: 5, factoryTitle: 'Лесопилка' },
                'Руда':              { cost: 180,   minCount: 5, factoryTitle: 'Рудник' },
                'Ртуть':             { cost: 360,   minCount: 3, factoryTitle: 'Лаборатория' },
                'Сера':              { cost: 360,   minCount: 3, factoryTitle: 'Залежи серы' },
                'Кристаллы':         { cost: 360,   minCount: 3, factoryTitle: 'Пещера кристаллов' },
                'Самоцветы':         { cost: 360,   minCount: 3, factoryTitle: 'Шахта самоцветов' },
                'Кожа':              { cost: 180,   minCount: 3, factoryTitle: 'Ферма' },
                'Мифриловая руда':   { cost: 460,   minCount: 3, factoryTitle: 'Мифриловая шахта' },
                'Обсидиан':          { cost: 2000,  minCount: 1, factoryTitle: 'Обсидиановая шахта' },
                'Волшебный порошок': { cost: 2074,  minCount: 1, factoryTitle: 'Фабрика магии' },
                'Мифрил':            { cost: 3325,  minCount: 1, factoryTitle: 'Литейный цех' },
                'Никель':            { cost: 1698,  minCount: 1, factoryTitle: 'Никелевый цех' },
                'Орихалк':           { cost: 11000, minCount: 1, factoryTitle: 'Плавильный цех' },
                'Сталь':             { cost: 759,   minCount: 2, factoryTitle: 'Сталелитейный цех' },
            },
            logDelimiter: '------------------------------',
            companies: {
                open: new Set(),
                unavailable: new Set()
            },
            intervalCounter: 0
        };

        var utils = {
            getDocFromString: function (response) {
                return new DOMParser().parseFromString(response, "text/html");
            },
            $ajax: function (method, url, params = {}) {
                return new Promise(function (resolve, reject) {
                    var xhr = new XMLHttpRequest();
                    xhr.onerror = reject;
                    //console.log(`I'm opening ${url}`);
                    xhr.open(method, url, true);
                    if (method.toLowerCase() === 'post') {
                        xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
                        xhr.onload = function () {
                            resolve(this.responseText);
                        };
                    } else if (method.toLowerCase() === 'get') {
                        var reader = new FileReader();
                        reader.addEventListener("loadend", function () {
                            resolve(reader.result);
                        });
                        xhr.responseType = "blob";
                        xhr.onload = function () {
                            reader.readAsText(xhr.response, "windows-1251");
                        };
                    }
                    xhr.send(params);
                });
            },
            log: function (data) {
                console.log(`${new Date().toLocaleString()}| ${data}`);
            },
            getCaptchaUrl: function (document) {
                return document.querySelector('img[name=imgcode]').getAttribute('src');
            },
            parseCaptcha: function (captchaUrl, serverUrl = globalVars.serverUrl) {
                var params = encodeURIComponent(captchaUrl);
                return this.$ajax('GET', `${serverUrl}/cap/${params}`);
            },
            sendCaptcha: function () {
                var workParams = globalVars.workParams;
                var params = this.stringifyParams(workParams);
                var url = `${globalVars.hwmUrl}/object_do.php`;
                utils.log(`Отправляю капчу по url: ${url}`, params);
                return this.$ajax('POST', url, params);
            },
            stringifyParams(params) {
                return Object
                  .keys(params)
                  .map((key) => `${key}=${params[key]}`)
                  .join('&')
                  ;
            },
            getWorkParams: function (doc, docStr) {
                var captchaInput = doc.querySelector('form[name="working"] input[type="text"]');
                utils.checkExistence(captchaInput, doc, 'Captcha input not found');

                var params = ['id', 'id2', 'idr', 'num', 'id3'].reduce((acc, curr) => {
                    const input = doc.querySelector(`input[name="${curr}"]`);
                    return {
                        ...acc,
                        [curr]: input && input.value,
                    }
                }, {});
                params.num = utils.getNumParamValue(docStr);

                return params;
            },
            getRandInt: function (min, max) {
                return Math.floor(Math.random() * (max - min + 1)) + min;
            },
            getFirstOpenFactoryUrl: function (doc) {
                var allLinks = [].filter.call(
                    doc.getElementsByTagName('a'),
                    (e) => e.innerHTML === '»»»'
                );
                if (allLinks.length > 0) {
                    var firstLink = allLinks[0];
                }
                return firstLink && firstLink.getAttribute('href');
            },
            getFactoriesOnMap: function (factoriesType = 'sh') {
                return utils.$ajax('GET', `https://www.heroeswm.ru/map.php?st=${factoriesType}`
                ).then((mapPage) => {
                    var doc = utils.getDocFromString(mapPage);
                    return doc.querySelectorAll('a[href*=object-info]:not([id])');
                });
            },
            parseFactories: function () {
                return Promise.all([
                    //parseFactoriesOnMap('mn'), // добыча не нужна для продажи ресурсов
                    utils.parseFactoriesOnMap('fc'),
                    utils.parseFactoriesOnMap('sh')
                ]);
            },
            parseFactoriesOnMap: function (type = 'sh') {
                return utils.getFactoriesOnMap(type).then((linkElems) => {
                    linkElems.forEach((linkElem) => {
                        var parent = linkElem.parentElement;
                        var color = parent.className;

                        var companies = globalVars.companies;
                        if (color === 'wbwhite') {
                            companies = companies.open;
                        } else if (color === 'wblight') {
                            companies = companies.unavailable;
                        } else {
                            companies = new Set();
                            console.log('Smth strange with color...');
                        }
                        var href = linkElem.getAttribute('href');
                        var companyId = +href.slice(href.lastIndexOf('=') + 1);
                        companies.add(companyId);
                    });
                });
            },
            findBestWork: function () { // TODO: REFACTORING
                var skip = false;
                var resultUrl = '';
                return getFactoriesOnMap('sh').then((url) => {
                    if (url) {
                        utils.log(`Самое выгодное - производство: ${url}`);
                        skip = true;
                        resultUrl = url;
                    } else {
                        utils.log(`Нет выгодных производств`);
                        return getFactoriesOnMap('fc');
                    }
                }).then((url) => {
                    if (skip) {
                        return;
                    }
                    if (url) {
                        utils.log(`Самое выгодное - обработка: ${url}`);
                        skip = true;
                        resultUrl = url;
                    } else {
                        utils.log(`Нет выгодных обработок`);
                        return getFactoriesOnMap('mn');
                    }
                }).then((url) => {
                    if (skip) {
                        return;
                    }
                    if (url) {
                        utils.log(`Самое выгодное - добыча: ${url}`);
                        resultUrl = url;
                    } else {
                        utils.log(`Очень странно, но нет свободных предприятий :/`);
                    }
                }).then(() => {
                    if (resultUrl) {
                        return utils.getFactoryPage(resultUrl.slice(resultUrl.lastIndexOf('=') + 1));
                    } else {
                        utils.log(`Что-то не так...`);
                    }
                }).then((factoryPage) => {
                    if (factoryPage && factoryPage.search(/Устройство на работу/i) !== -1) {
                        var factoryDocument = utils.getDocFromString(factoryPage);
                        globalVars.workParams = utils.getWorkParams(factoryDocument, factoryPage);
                    } else {
                        throw new Error('На производстве нет формы "Устройство на работу"');
                    }
                });

                function getFactoriesOnMap(type = 'sh') {
                    return utils.$ajax('GET', `https://www.heroeswm.ru/map.php?st=${type}`
                    ).then((mapPageFactories) => {
                        return onMapGetCallback(mapPageFactories);
                    });
                }

                /**
                 * Returns a Promise resolved with [url] OR [undefined]
                 */
                function onMapGetCallback(mapPageFactories) {
                    var doc = utils.getDocFromString(mapPageFactories);
                    var firstOpenProdUrl = utils.getFirstOpenFactoryUrl(doc);
                    if (firstOpenProdUrl) {
                        globalVars.firstOpenProdUrl = firstOpenProdUrl;
                    }

                    return new Promise(function (resolve) {
                        resolve(firstOpenProdUrl);
                    });
                }
            },
            getFactoryPage: function (factoryId) {
                return utils.$ajax('GET', `https://www.heroeswm.ru/object-info.php?id=${factoryId}`);
            },
            getCompanyParams: function (companyPage) {
                var doc = utils.getDocFromString(companyPage);

                return {
                    balance: getBalance(doc),
                    salary: getSalary(doc),
                    freePlaces: getFreePlaces(doc)
                };

                function getBalance(doc) {
                    var keyword = 'Баланс';
                    var balanceTextElem = [].filter.call(
                        doc.getElementsByTagName('td'),
                        (e) => e.innerText.slice(0, keyword.length) === keyword
                    )[0];

                    var balanceElem = balanceTextElem.nextSibling.querySelector('img[title="Золото"]').parentElement.nextSibling.firstElementChild;
                    var balance = parseInt(balanceElem.innerText.replace(/,/g, ''), 10);

                    return balance || null;
                }

                function getSalary(doc) {
                    var keyword = 'Зарплата';
                    var salaryTextElem = [].filter.call(
                        doc.getElementsByTagName('td'),
                        (e) => e.innerText.slice(0, keyword.length) === keyword
                    )[0];

                    var salaryElem = salaryTextElem.nextSibling.querySelector('img[title="Золото"]').parentElement.nextSibling.firstElementChild;
                    var salary = parseInt(salaryElem.innerText.replace(/,/g, ''), 10);

                    return salary || null;
                }

                function getFreePlaces(doc) {
                    var keyword = 'Свободных мест';
                    var freePlaces = [].filter.call(
                        doc.getElementsByTagName('b'),
                        (e) => e.previousSibling && e.previousSibling.textContent.slice(0, keyword.length) === keyword
                    )[0];
                    freePlaces = parseInt(freePlaces.innerText);

                    return freePlaces || null;
                }
            },
            getCharParams: function (charId = globalVars.charParams.id) {
                return utils.$ajax('GET', `https://www.heroeswm.ru/pl_info.php?id=${charId}`
                ).then((charPage) => {
                    var doc = utils.getDocFromString(charPage);
                    var wbs = doc.querySelectorAll('td.wb');
                    var paramsElem = wbs[1].querySelector('tr').children;
                    var paramsResources = wbs[10].getElementsByTagName('b');

                    var params = {};
                    for (var i = 0; i < paramsElem.length; i += 2) {
                        var elem = paramsElem[i].querySelector('img').getAttribute('title');
                        params[elem] = +paramsElem[i + 1]
                            .querySelector('b')
                            .innerText
                            .replace(/,/g, '');
                    }
                    [].forEach.call(paramsResources, (res) => {
                        params[res.innerText] = +res.nextSibling.textContent.replace(/: /g, '');
                    });

                    return params;
                });
            },
            getResourcesCostSum: function (resourcesObj = globalVars.resources) {
                var resources = globalVars.resources;
                return Object.keys(resourcesObj).reduce((acc, curr) => {
                    return acc + resourcesObj[curr].minCount * resources[curr].cost;
                }, 0);
            },
            getFactoriesTitles: (resources) => {
                return Object.keys(resources).reduce((accum, curr) => {
                    if (curr === 'Золото') return accum;
                    return accum[curr] = globalVars.resources[curr].factoryTitle, accum;
                }, {});
            },
            checkExistence: (item, dataAttachToError, errorMessage) => {
                if (!item) {
                    var e = new Error(errorMessage);
                    e.dataAttachToError = dataAttachToError;
                    throw e;
                }
            },
            logMoney: (params) => {
                utils.log(`Суммарно денег: ${Object.keys(params).reduce((accum, curr) => {
                    if (globalVars.resources[curr]) {
                        var cost = globalVars.resources[curr].cost;
                    }
                    cost = cost || 0;
                    return accum + params[curr] * cost;
                }, 0)}`);
            },
            getNumParamValue: (docStr) => {
                const s1 = `document.getElementById("num").value = `;
                const s2 = `; var l = document.getElementById("code").value.length`;
                const numValueExpression = docStr.slice(
                  docStr.indexOf(s1) + s1.length,
                  docStr.indexOf(s2),
                );
                return eval(numValueExpression);
            },
        };

        var game = {
            startSellElements: function () {
                if (globalVars.sellElementsInterval) {
                    game.stopSellElements();
                }
                utils.log(`Начинаю продавать элементы`);
                globalVars.statuses.sellElements = true;
                utils.parseFactories().then(() => {
                    globalVars.sellElementsInterval = setInterval(() => {
                        var companiesOpen = globalVars.companies.open;
                        var companiesUnavailable = globalVars.companies.unavailable;

                        companiesOpen.forEach((companyId) => {
                            //utils.log('Open company, sell: ' + companyId);
                            game.checkCompanyForSell(true, companyId);
                        });

                        if (globalVars.intervalCounter++ % 10 === 0) {
                            companiesUnavailable.forEach((companyId) => {
                                //utils.log('Unavailable company, sell: ' + companyId);
                                game.checkCompanyForSell(false, companyId);
                            });
                        }
                    }, 750);
                }).catch((e) => {
                    utils.log(`sellElementsLoop crashed:`);
                    console.log(e);
                });
            },
            checkCompanyForSell: function (isOpen, companyId) {
                return utils.$ajax('GET', `https://www.heroeswm.ru/object-info.php?id=${companyId}`
                ).then((companyPage) => {
                    var isCompanyInsolvent = (() => {
                        var companyParams = utils.getCompanyParams(companyPage);
                        return companyParams.balance > companyParams.salary && companyParams.freePlaces > 0;
                    })();

                    if (!isCompanyInsolvent && isOpen) {
                        utils.log(`Компания ${companyId} не готова к покупкам`);
                        globalVars.companies.open.delete(companyId);
                        globalVars.companies.unavailable.add(companyId);
                        return;
                    } else if (isCompanyInsolvent && !isOpen) {
                        utils.log(`Компания ${companyId} теперь готова к покупкам`);
                        globalVars.companies.unavailable.delete(companyId);
                        globalVars.companies.open.add(companyId);
                        return;
                    }
                    var doc = utils.getDocFromString(companyPage);
                    var forms = doc.querySelectorAll(`form[action="${globalVars.sellResUrl}"]`);
                    if (forms.length > 0) {
                        utils.log(`Успех! Можно продать ресурсы для компании ${companyId}`);
                        return Promise.all(
                            [].map.call(forms, game.sellResCallback)
                        ).then(() => {
                            return utils.getCharParams();
                        }).then((charParams) => {
                            utils.logMoney(charParams);
                        });
                    }
                });
            },
            sellResCallback: function (form) { // TODO: CHECK
                form.count.value = 99;
                var names = ['obj_id', 'check_code', 'res_id', 'count'];
                var formData = names.reduce((accum, curr) => {
                    var inputVal = form.querySelector(`input[name=${curr}]`).value;
                    return accum.concat(`${curr}=${encodeURIComponent(inputVal)}`);
                }, []).join('&');

                return utils.$ajax('POST', `/${globalVars.sellResUrl}`, formData);
            },
            stopSellElements: function () {
                globalVars.statuses.sellElements = false;
                utils.log(`Прекращаю продавать элементы`);
                clearInterval(globalVars.sellElementsInterval);
                delete globalVars.sellElementsInterval;
            },
            checkWorkStatus: function () {
                utils.log(`Проверка, может, я уже устроен?`);
                return utils.$ajax('GET', 'https://www.heroeswm.ru/home.php'
                ).then((charPage) => charPage.includes('Вы нигде не работаете.'));
            },
            getWork: function () {
                //game.stopSellElements();
                return game.checkWorkStatus().then((workStatus) => {
                    if (workStatus) {
                        utils.log(`Устраиваюсь на работу`);
                        return utils.$ajax('GET', 'https://www.heroeswm.ru/map.php?st=mn');
                    } else {
                        throw new Error('Уже устроен');
                    }
                }).then((mapPage) => { // открыть карту "Обработка"

                    var doc = utils.getDocFromString(mapPage);
                    var firstOpenProdUrl = utils.getFirstOpenFactoryUrl(doc);
                    if (firstOpenProdUrl) {
                        globalVars.firstOpenProdUrl = firstOpenProdUrl;
                        utils.log(`Первое открытое предприятие: ${firstOpenProdUrl}`);

                        return utils.$ajax('GET', `/${firstOpenProdUrl}`); // открыть ссылку первого открытого предприятия
                    } else {
                        throw new Error('Среди обработок нет открытых предприятий, crashed.');
                    }

                }).then((firstProdPage) => { // обработка страницы первого открытого предприятия

                    var doc = utils.getDocFromString(firstProdPage);
                    var captchaUrl = utils.getCaptchaUrl(doc); // получить относительную ссылку капчи
                    if (!captchaUrl) {
                        throw new Error('Captcha not found on page');
                    }
                    captchaUrl = `${globalVars.hwmUrl}/${captchaUrl}`; // абсолютная ссылка капчи
                    utils.log(`Ссылка на капчу: ${captchaUrl}, отправляю на локалхост`);

                    return utils.parseCaptcha(captchaUrl); // отправить капчу парситься на локалхост

                }).then((captchaText) => {  // после того, как капчу распарсили, передаю ее дальше;
                    // ищу максимально выгодное предприятие
                    utils.log(`Текст капчи: ${captchaText}`);
                    utils.log(`Ищу самое выгодное предприятие для устройства`);
                    return new Promise(function (resolve) {
                        return utils.findBestWork().then(() => {
                            resolve(captchaText);
                        });
                    });

                }).then((captchaText) => { // проверяю текст капчи и отправляю на сервер

                    if (captchaText.length !== 6) { // проверяю
                        throw new Error('Wrong captcha');
                    }
                    globalVars.workParams.code = captchaText;
                    //utils.GM_addData('hwm_workers_guild_log', `Get captcha: ${captchaText}`); // логаю

                    utils.log(`Составляю запрос и отправляю капчу на сервер`);
                    return utils.sendCaptcha(captchaText); // отправляю

                }).catch((e) => {
                    if (e.message === 'Уже устроен') {
                        return new Promise(function (resolve) {
                            resolve(e.message);
                        });
                    }
                    utils.log(`Ошибка в функции getWork`);
                    console.log(e);
                });
            },
            startGetWorkLoop: function () {
                game.getWork().then((afterCaptchaPage) => {
                    utils.log(`Ответ с сервера пришел`);
                    if (!afterCaptchaPage) {
                        throw new Error('There is no page after captcha input');
                    }
                    if (afterCaptchaPage.includes('Вы устроены на работу.')) {
                        var workDelay = (60 + utils.getRandInt(1, 15)) * 60000;
                        var nextWorkTime = new Date(+new Date() + workDelay);
                        setTimeout(game.startGetWorkLoop, workDelay);

                        utils.log(`${nextWorkTime} - время следующего устройства`);
                        console.log(globalVars.logDelimiter);
                    } else if (afterCaptchaPage.includes('Введен неправильный код.')) {
                        utils.log(`Введен неправильный код. Капча: ${globalVars.workParams.code}`);
                    } else if (afterCaptchaPage === 'Уже устроен') {
                        utils.log(`Да, я уже устроен`);
                        workDelay = 10 * 60000;
                        setTimeout(game.startGetWorkLoop, workDelay);
                    }
                });
            },
            startBuyElements: function () {
                setInterval(() => {
                    utils.getCharParams().then((charParams) => {
                        var toBuy = {};
                        var resources = globalVars.resources;
                        Object.keys(resources).forEach((res) => {
                            var resDiff = (charParams[res] || 0) - resources[res].minCount;
                            if (resDiff < 0) {
                                toBuy[res] = -1 * resDiff;
                            }
                        });
                        var totalCost = utils.getResourcesCostSum();
                        if (charParams['Золото'] >= totalCost) {
                            return game.buyResources(toBuy);
                        } else {
                            utils.log(`На закупку не хватает ${totalCost - charParams['Золото']}`);
                        }
                    });
                }, 5 * 1000);
            },
            getCharId: function () {
                return utils.$ajax('GET', `https://www.heroeswm.ru/home.php`
                ).then((homePage) => {
                    var doc = utils.getDocFromString(homePage);
                    var charLink = doc.querySelector('center > a.pi[href*="pl_info.php?id="]');
                    if (charLink) {
                        var href = charLink.getAttribute('href');
                        globalVars.charParams.id = href.slice(href.lastIndexOf('=') + 1);
                    } else {
                        var e = new Error('No char ID on homepage');
                        e.doc = doc;
                        throw e;
                    }
                });
            },
            buyResFromDoc: (doc, amount) => {
                var buyResForm = doc.querySelector('form[name="buy_res"]');
                utils.checkExistence(buyResForm, doc, 'No "buy_res" form on page');

                var amountAllowed;
                var howMuchCanIBuyElem = [].find.call(
                    buyResForm.querySelectorAll('td.wb[align="center"]'),
                    (td) => td.innerText.trim().includes('Можете купить:')
                ).querySelector('b');
                if (!howMuchCanIBuyElem) { // Не могу купить
                    amountAllowed = 0;
                    return;
                } else {
                    amountAllowed = +howMuchCanIBuyElem.innerText.replace(/,/g, '');
                }

                var flashParamsElem = buyResForm.querySelector('object > param[name="FlashVars"]');
                utils.checkExistence(flashParamsElem, doc, 'No "FlashVars" <param> on page');

                var buyResParams = flashParamsElem.getAttribute('value');
                utils.checkExistence(buyResParams, flashParamsElem, 'Empty value attr in flash <param>');
                buyResParams = buyResParams.split('|');

                buyResParams = {
                    //rand1: NaN,
                    pl_id: buyResParams[7],
                    obj_id: buyResParams[5],
                    check_code: buyResParams[6],
                    count: amount
                };
                var POST_query = Object.keys(buyResParams).reduce((accum, curr) => {
                    return accum + `&${curr}=${buyResParams[curr]}`;
                }, `rand1=NaN`);

                if (amountAllowed >= amount) {
                    return utils.$ajax('POST', 'https://www.heroeswm.ru/buy_res.php', POST_query);
                }
            },
            buyResOnMap: function (factoryLink, amount) {
                return utils.$ajax('GET', factoryLink).then((factoryPage) => {
                    var doc = utils.getDocFromString(factoryPage);
                    return game.buyResFromDoc(doc, amount);
                });
            },
            buyResources: function (toBuy) {
                var factoriesThatINeed = utils.getFactoriesTitles(toBuy);
                var factoriesParsed = {};

                function updateFactories(linkElems) {
                    linkElems.forEach((a) => {
                        var resKey = Object.keys(factoriesThatINeed).filter((key) => {
                            return factoriesThatINeed[key] === a.innerText;
                        })[0];

                        if (resKey) {
                            factoriesParsed[resKey] = {
                                factoryTitle: a.innerText,
                                link: a.getAttribute('href')
                            };
                        }
                    });
                }

                return utils.getFactoriesOnMap('mn').then((linkElems) => { // ДОБЫЧА
                    updateFactories(linkElems);

                    return utils.getFactoriesOnMap('fc'); // ОБРАБОТКА
                }).then((linkElems) => {
                    updateFactories(linkElems);

                }).then(() => {
                    return Promise.all(Object.keys(factoriesParsed).map((res) => {
                        utils.log(`Покупаю ${toBuy[res]} шт. "${res}" на предприятии `);
                        return game.buyResOnMap(factoriesParsed[res].link, toBuy[res]);
                    }));
                });
            },
        };

        // var regexPattern = /Район:[\s\S]*?<a[\s\S]*?>[\s]{2}([\s\S]+?)<\/a>/i;
        // result = response.match(regexPattern)[1]; // <--- RETURN THIS

        var getOptionsElem = () => {
            var existentElem = document.querySelector('.bot-options');
            if (existentElem) {
                return existentElem;
            }

            var wrapper = document.createElement('div');
            wrapper.className = 'bot-options';

            var sellButton = (() => {
                var sellButton = document.createElement('button');
                sellButton.id = 'sellButton';
                sellButton.addEventListener('click', function () {
                    var status = globalVars.statuses.sellElements;
                    if (status) {
                        game.stopSellElements();
                    } else {
                        game.startSellElements();
                    }
                    updateOptions();
                });
                return sellButton;
            })();

            var workButton = (() => {
                var workButton = document.createElement('button');
                workButton.id = 'workButton';
                workButton.disabled = true;
                return workButton;
            })();

            wrapper.appendChild(sellButton);
            wrapper.appendChild(workButton);

            var s = wrapper.style;
            s.position = 'fixed';
            s.left = '20px';
            s.top = '20px';

            return wrapper;
        };

        function updateOptions() {
            document.getElementById('sellButton').innerText = `Продавать элементы: ${globalVars.statuses.sellElements}`;
            document.getElementById('workButton').innerText = `Устроен на работу: ${globalVars.statuses.work}`;
        }

        function showOnlyOptions() {
            document.querySelector('table').hidden = true;
            document.querySelector('center').hidden = true;
            document.body.appendChild(getOptionsElem());
        }

        function init() {
            showOnlyOptions();
            myBot.getCharId().then(() => {
                myBot.work();
                myBot.buyStart();
                myBot.sellStart();
                updateOptions();
            });
        }

        return {
            work: game.startGetWorkLoop,
            sellStart: game.startSellElements,
            buyStart: game.startBuyElements,
            sellStop: game.stopSellElements,
            getCharId: game.getCharId,
            init
        };
    })();

    myBot.init();
    setTimeout(() => {
        location.reload();
    }, 5 * 60 * 1000);
})();