Ошибка при записи в базу

3 posts in this topic

INewBRO
Новичок

Хотел записать в базу данные об игроке (пароль, ник и т.д) Но происходит ошибка и оно не записывается. Я написал чтобы ошибки сохранялись в файл. Комментарием отметил где ошибка

Спойлер


#include <a_samp>

#include <fix>
#include <a_mysql>
#include <streamer>
#include <Pawn.CMD>
#include <sscanf2>
#include <foreach>
#include <Pawn.Regex>
#include <crashdetect>

#define     MYSQL_HOST  "localhost"
#define     MYSQL_USER  "root"
#define     MYSQL_PASS  ""
#define     MYSQL_BASE  "inewrp"

#define SCM     SendClientMessage
#define SCMTA   SendClientMessageToAll
#define SPD     ShowPlayerDialog

#define COLOR_WHITE 0xFFFFFFFF
#define COLOR_RED   0xFF0000FF



main()
{
    print("\n----------------------------------");
    print("-------NEW PROJECT STARTED--------");
    print("----------------------------------\n");
}

new MySQL:dbHandle;


enum player
{
    ID,
    NAME[MAX_PLAYER_NAME],
    PASSWORD[65],
    SALT[10],
    EMAIL[65],
    REF,
    SEX,
    RACE,
    AGE,
    SKIN,
    REGDATA[13],
    REGIP[16],
}
new player_info[MAX_PLAYERS][player];

enum dialogs
{
    DLG_NONE,
    DLG_REG,
    DLG_REGEMAIL,
    DLG_REGREF,
    DLG_REGSEX,
    DLG_REGRACE,
    DLG_REGAGE,
    DLG_LOG,
}

public OnGameModeInit()
{
    ConnectMySQL();
    return 1;
}

stock ConnectMySQL()
{
    dbHandle = mysql_connect(MYSQL_HOST, MYSQL_USER, MYSQL_PASS, MYSQL_BASE);
    switch(mysql_errno())
    {
        case 0: print("Подключение к MySQL успешно");
        default: print("MySQL не подключён");
    }
    mysql_log(ERROR | WARNING);
    mysql_set_charset("cp1251");
}

public OnGameModeExit()
{
    return 1;
}

public OnPlayerRequestClass(playerid, classid)
{
    return 1;
}

public OnPlayerConnect(playerid)
{
    GetPlayerName(playerid, player_info[playerid][NAME], MAX_PLAYER_NAME);
    static const fmt_query[] = "SELECT `id` FROM `users` WHERE `name` = '%s'";
    new query[sizeof(fmt_query)+(-2+MAX_PLAYER_NAME)];
    format(query, sizeof(query), fmt_query, player_info[playerid][NAME]);
    mysql_tquery(dbHandle, query, "CheckRegistration""i", playerid);
    return 1;
}

forward CheckRegistration(playerid);
public CheckRegistration(playerid)
{
    new rows;
    cache_get_row_count(rows);
    if(rows) ShowLogin(playerid);
    else ShowRegistration(playerid);
    
}

stock ShowLogin(playerid)
{
    SCM(playerid, COLOR_WHITE, "Игрок зарегистрирован");
}

stock ShowRegistration(playerid)
{
    new dialog[386+(-2+MAX_PLAYER_NAME)];
    format(dialog, sizeof(dialog),
        "{FFFFFF}Уважаемый {0f97ff}%s{FFFFFF}, мы рады видеть вас на сервере {ffaa3b}INewRolePlay{FFFFFF}\n\
        Аккаунт с таким именем не зарегистрирован\n\
        Для начала игры пройдите регистрацию\n\n\
        Напишите пароль для вашего акккаунта и нажмите \"Готово\"\n\
        {ff6a00}\tУсловия:\n\
        \t•Пароль должен быть от 8 до 32-х символов\n\
        \t•Пароль должен быть только из цифр и латинских символов любого регистра",
    player_info[playerid][NAME]
    );
    SPD(playerid, DLG_REG, DIALOG_STYLE_INPUT, "{0f97ff}Регистрация{FFFFFF} • Введите пароль", dialog, "Готово""Назад");
}

public OnPlayerDisconnect(playerid, reason)
{
    return 1;
}

public OnPlayerSpawn(playerid)
{
    return 1;
}

public OnPlayerDeath(playerid, killerid, reason)
{
    return 1;
}

public OnVehicleSpawn(vehicleid)
{
    return 1;
}

public OnVehicleDeath(vehicleid, killerid)
{
    return 1;
}

public OnPlayerText(playerid, text[])
{
    return 1;
}

public OnPlayerCommandText(playerid, cmdtext[])
{
    return 0;
}

public OnPlayerEnterVehicle(playerid, vehicleid, ispassenger)
{
    return 1;
}

public OnPlayerExitVehicle(playerid, vehicleid)
{
    return 1;
}

public OnPlayerStateChange(playerid, newstate, oldstate)
{
    return 1;
}

public OnPlayerEnterCheckpoint(playerid)
{
    return 1;
}

public OnPlayerLeaveCheckpoint(playerid)
{
    return 1;
}

public OnPlayerEnterRaceCheckpoint(playerid)
{
    return 1;
}

public OnPlayerLeaveRaceCheckpoint(playerid)
{
    return 1;
}

public OnRconCommand(cmd[])
{
    return 1;
}

public OnPlayerRequestSpawn(playerid)
{
    return 1;
}

public OnObjectMoved(objectid)
{
    return 1;
}

public OnPlayerObjectMoved(playerid, objectid)
{
    return 1;
}

public OnPlayerPickUpPickup(playerid, pickupid)
{
    return 1;
}

public OnVehicleMod(playerid, vehicleid, componentid)
{
    return 1;
}

public OnVehiclePaintjob(playerid, vehicleid, paintjobid)
{
    return 1;
}

public OnVehicleRespray(playerid, vehicleid, color1, color2)
{
    return 1;
}

public OnPlayerSelectedMenuRow(playerid, row)
{
    return 1;
}

public OnPlayerExitedMenu(playerid)
{
    return 1;
}

public OnPlayerInteriorChange(playerid, newinteriorid, oldinteriorid)
{
    return 1;
}

public OnPlayerKeyStateChange(playerid, newkeys, oldkeys)
{
    return 1;
}

public OnRconLoginAttempt(ip[], password[], success)
{
    return 1;
}

public OnPlayerUpdate(playerid)
{
    return 1;
}

public OnPlayerStreamIn(playerid, forplayerid)
{
    return 1;
}

public OnPlayerStreamOut(playerid, forplayerid)
{
    return 1;
}

public OnVehicleStreamIn(vehicleid, forplayerid)
{
    return 1;
}

public OnVehicleStreamOut(vehicleid, forplayerid)
{
    return 1;
}

public OnDialogResponse(playerid, dialogid, response, listitem, inputtext[])
{
    switch(dialogid)
    {
        case DLG_REG:
        {
            if(response)
            {
                if(!strlen(inputtext))
                {
                    ShowRegistration(playerid);
                    return SCM(playerid, COLOR_RED, "-Ошибка- {FFFFFF} Введите в поле ниже пароль");
                }
                if(strlen(inputtext) < 8 || strlen(inputtext) > 32)
                {
                    ShowRegistration(playerid);
                    return SCM(playerid, COLOR_RED, "-Ошибка- {FFFFFF} Длина пароля должна быть от 8 до 32-х символов");
                }
                new regex:rg_passwordcheck = regex_new("^[a-zA-Z0-9]{1,}$");
                if(regex_check(inputtext, rg_passwordcheck))
                {
                    new salt[11];
                    for(new i; i < 10; i++)
                    {
                        salt[i] = random(79) + 47;
                    }
                    salt[10] = 0;
                    SHA256_PassHash(inputtext, salt, player_info[playerid][PASSWORD], 65);
                    strmid(player_info[playerid][SALT], salt, 01111);
                    SPD(playerid, DLG_REGEMAIL, DIALOG_STYLE_INPUT, "{0797FF}Регистрация{FFFFFF} • Введите EMAIL",
                        "{FFFFFF}Введите ваш Email адрес ниже и нажмите \"Готово\"\n\
                        Если вы потеряете доступ к аккаунту вы можете восстановить его",
                    "Готово","");
                }
                else
                {
                    ShowRegistration(playerid);
                    return SCM(playerid, COLOR_RED, "-Ошибка- {FFFFFF} Пароль может состоять только из латинских сиволов и чисел");
                }
                regex_delete(rg_passwordcheck);
            }
            else
            {
                SCM(playerid, COLOR_RED, "-Подсказка- {FFFFFF} Используйте \"/q\", для выхода");
                SPD(playerid, -10" "" "" """);
                return Kick(playerid);
            }
        }
        case DLG_REGEMAIL:
        {
            if(!strlen(inputtext))
            {
                SPD(playerid, DLG_REGEMAIL, DIALOG_STYLE_INPUT, "{0797FF}Регистрация{FFFFFF} • Введите EMAIL",
                    "{FFFFFF}Введите ваш Email адрес ниже и нажмите \"Готово\"\n\
                    Если вы потеряете доступ к аккаунту вы можете восстановить его",
                "Готово","");
                return SCM(playerid, COLOR_RED, "-Ошибка- {FFFFFF} Введите в поле ниже ваш Email!");
            }
            new regex:rg_emailcheck = regex_new("^[a-zA-Z0-9.-_]{1,43}@[a-zA-Z]{1,12}.{1,8}$");
            if(regex_check(inputtext, rg_emailcheck))
            {
                strmid(player_info[playerid][EMAIL], inputtext, 0, strlen(inputtext), 64);
                SPD(playerid, DLG_REGREF, DIALOG_STYLE_INPUT, "{0797FF}Регистрация{FFFFFF} • Введите реферала",
                    "{ff6a00}Если вы зашли на сервер по приглашению{FFFFFF} \n\
                    укажите ник пригласившего.\n\
                    Если вы не желаете его вводить нажмите \"Пропустить\"",
                "Готово""Пропустить");
            }
            else
            {
                SPD(playerid, DLG_REGEMAIL, DIALOG_STYLE_INPUT, "{0797FF}Регистрация{FFFFFF} • Введите EMAIL",
                    "{FFFFFF}Введите ваш Email адрес ниже и нажмите \"Готово\"\n\
                    Если вы потеряете доступ к аккаунту вы можете восстановить его",
                "Готово","");
                return SCM(playerid, COLOR_RED, "-Ошибка- {FFFFFF} Проверьте правильность вашего Email адреса");
            }
            regex_delete(rg_emailcheck);
        }
        case DLG_REGREF:
        {
            if(response)
            {
                new regex:rg_refcheck = regex_new("^[a-zA-Z_]{4,24}$");
                if(regex_check(inputtext, rg_refcheck))
                {
                    static const fmt_query[] = "SELECT * FROM `users` WHERE `name` = '%s'";
                    new query[sizeof(fmt_query)+(-2+MAX_PLAYER_NAME)];
                    format(query, sizeof(query), fmt_query, inputtext);
                    mysql_tquery(dbHandle, query, "CheckReferal""is", playerid, inputtext);
                }
                else
                {
                    SPD(playerid, DLG_REGREF, DIALOG_STYLE_INPUT, "{0797FF}Регистрация{FFFFFF} • Введите реферала",
                        "{ff6a00}Если вы зашли на сервер по приглашению{FFFFFF} \n\
                        укажите ник пригласившего.\n\
                        Если вы не желаете его вводить нажмите \"Пропустить\"",
                    "Готово""Пропустить");
                    return SCM(playerid, COLOR_RED, "-Ошибка- {FFFFFF} Проверьте ник пригласившего вас игрока и попробуйте снова");
                }
                regex_delete(rg_refcheck);
            }
            else
            {
                SPD(playerid, DLG_REGSEX, DIALOG_STYLE_MSGBOX, "{0797FF}Регистрация • {FFFFFF} Выберите пол персонажа",
                    "{FFFFFF}Пожалуйста, выберите пол вашего персонажа перед началом игры",
                "Мужской""Женский");
            }
        }
        case DLG_REGSEX:
        {
            if(response) player_info[playerid][SEX] = 1;
            else player_info[playerid][SEX] = 2;
            SPD(playerid, DLG_REGRACE, DIALOG_STYLE_LIST, "{0797FF}Регистрация{FFFFFF} • Выберите расу персонажа",
                "Негроидная\n\
                Европеоидная\n\
                Многолоидная/Азтатская",
            "Готово""");
        }
        case DLG_REGRACE:
        {
            switch(listitem)
            {
                case 0: player_info[playerid][RACE] = 1;
                case 1: player_info[playerid][RACE] = 2;
                case 2: player_info[playerid][RACE] = 3;
            }
            SPD(playerid, DLG_REGAGE, DIALOG_STYLE_INPUT, "{0797FF}Регистрация{FFFFFF} • Выберите возраст персонажа",
                "{FFFFFF}Выберите возраст вашего персонажа\n\
                {ff6a00}\t• Возраст должен быть от 18 до 60-и",
            "Готово""");
        }
        case DLG_REGAGE:
        {
            if(!strlen(inputtext))
            {
                SPD(playerid, DLG_REGAGE, DIALOG_STYLE_INPUT, "{0797FF}Регистрация{FFFFFF} • Выберите возраст персонажа",
                    "Выберите возраст вашего персонажа:\n\
                    {ff6a00}\t• Возраст должен быть от 18 до 60-и",
                "Готово""");
                return SCM(playerid, COLOR_RED, "-Ошибка- {FFFFFF} Введите ваш возраст в поле ниже");
            }
            if(strval(inputtext) < 18 || strval(inputtext) > 60)
            {
                SPD(playerid, DLG_REGAGE, DIALOG_STYLE_INPUT, "{0797FF}Регистрация{FFFFFF} • Выберите возраст персонажа",
                    "{FFFFFF}Выберите возраст вашего персонажа\n\
                    {ff6a00}\t•Возраст должен быть от 18 до 60-и",
                "Готово""");
                return SCM(playerid, COLOR_RED, "-Ошибка-{FFFFFF} Возраст должен быть от 18 до 60-и лет");
            }
            player_info[playerid][AGE] = strval(inputtext);
            new reqmaleskins[9][4] =
            {
                {19,21,22,28},
                {24,25,36,67},
                {14,142,182,184},
                {29,96,101,26},
                {2,37,72,202},
                {1,3,234,290},
                {23,60,170,180},
                {20,47,48,206},
                {44,58,132,229}
            };
            new reqfemaleskins[9][2] = 
            {
                {13,69},
                {9,190},
                {10,218},
                {41,56},
                {31,151},
                {39,89},
                {169,193},
                {207,225},
                {54,130}
            };
            new newskinindex;
            switch(player_info[playerid][RACE])
            {
                case 1: {}
                case 2: newskinindex+=3;
                case 3: newskinindex+=6;
            }
            switch(player_info[playerid][AGE])
            {
                case 18..29: {}
                case 30..45: newskinindex++;
                case 46..60: newskinindex+=2;
            }
            if(player_info[playerid][SEX] == 1) player_info[playerid][SKIN] = reqmaleskins[newskinindex][random(4)];
            else player_info[playerid][SKIN] = reqfemaleskins[newskinindex][random(2)];
            new Year, Month, Day;
            getdate(Year, Month, Day);
            new date[13];
            format(date, sizeof(date), "%02d.%02d.%d", Day, Month, Year);
            new ip[16];
            GetPlayerIp(playerid, ip, sizeof(ip));
            static const fmt_query[] = "INSERT INTO `users` (`name`, `password`, `salt`, `email`, `ref`, `sex`, `race`, `age`, `skin`, `regdata`, `regip`) VALUE ('%s', '%s', '%s', '%s', '%d', '%d', '%d', '%d', '%s', '%s')";
            new query[sizeof(fmt_query)+(-2+MAX_PLAYER_NAME)+(-2+64)+(-2+10)+(-2+64)+(-2+8)+(-2+1)+(-2+1)+(-2+2)+(-2+3)+(-2+12)+(-2+15)];
            format(query, sizeof(query), fmt_query, player_info[playerid][NAME], player_info[playerid][PASSWORD], player_info[playerid][SALT], player_info[playerid][EMAIL], player_info[playerid][REF], player_info[playerid][SEX], player_info[playerid][RACE], player_info[playerid][AGE], player_info[playerid][SKIN], date, ip);
            mysql_query(dbHandle, query);//Пишет что ошибка тут
        }
    }
    return 1;
}

forward CheckReferal(playerid, referal[]);
public CheckReferal(playerid, referal[])
{
    new rows;
    cache_get_row_count(rows);
    if(rows)
    {
        new refid;
        cache_get_value_name_int(0"id", refid);
        player_info[playerid][REF] = refid;
        SPD(playerid, DLG_REGSEX, DIALOG_STYLE_MSGBOX, "{0797FF}Регистрация • {FFFFFF} Выберите пол персонажа",
            "{FFFFFF}Пожалуйста, выберите пол вашего персонажа перед началом игры",
        "Мужской""Женский");
    }
    else
    {
        SPD(playerid, DLG_REGREF, DIALOG_STYLE_INPUT, "{0797FF}Регистрация{FFFFFF} • Введите реферала",
            "{ff6a00}Если вы зашли на сервер по приглашению{FFFFFF} \n\
            укажите ник пригласившего.\n\
            Если вы не желаете его вводить нажмите \"Пропустить\"",
        "Готово""Пропустить");
        return SCM(playerid, COLOR_RED, "-Ошибка- {FFFFFF} Такого аккаунта не существует");
    }
    return 1;
}

public OnPlayerClickPlayer(playerid, clickedplayerid, source)
{
    return 1;
}


 

Лог:

Цитата

[19:56:45] [ERROR] error #1136 while executing query "INSERT INTO `users` (`name`, `password`, `salt`, `email`, `ref`, `sex`, `race`, `age`, `skin`, `regdata`, `regip`) VALUE ('iiiiiiiiiiiiiiii', '068B01339F1813D72687ED138959D32C4A876C55EFEEAC04683381F51211B686', 'Q]H:}pJXseisah@gsad', 'isah@gsad', '0', '1', '3', '18', 'ґ', '25.10.2024')": Column count doesn't match value count at row 1 (E:\Server\gamemodes\project.pwn:496)

 

Edited by Cawfee

Share this post


Link to post
Share on other sites
Доналдо Фарекелка
Постоянный

Здравствуйте, не знаю, как вы хотите это сделать, но в своём бы моде я записал бы так:

 

format(query, sizeof(query), "INSERT INTO `users` (`name`, `password`, `salt`, `email`, `ref`, `sex`, `race`, `age`, `skin`, `regdata`, `regip`) VALUES ('%s','%s','%s','%s','%d', '%d', '%d', '%d', '%d', '%s','%s')"player_info[playerid][NAME], player_info[playerid][PASSWORD], player_info[playerid][SALT], player_info[playerid][EMAIL], player_info[playerid][REF], player_info[playerid][SEX], player_info[playerid][RACE], player_info[playerid][AGE], player_info[playerid][SKIN], date, ip);
mysql_tquery(dbHandle, query);

Во-первых, твой способ +- муторный, а во-вторых, ошибка в том, что у вас неравное кол-во столбцов(11-10).
 

Цитата

Column count doesn't match value count at row 1 - Количество столбцов не соответствует количеству значений в строке 1

 

Edited by Доналдо Фарекелка

Share this post


Link to post
Share on other sites
Kutuzov
Новичок

@INewBRO С ответом, который тебе дали, я согласен. Но не крепи сюда полностью весь код который у тебя есть. Прикрепи только тот участок кода, где проблема.

Например:

static const fmt_query[] = "INSERT INTO `users` (`name`, `password`, `salt`, `email`, `ref`, `sex`, `race`, `age`, `skin`, `regdata`, `regip`) VALUE ('%s', '%s', '%s', '%s', '%d', '%d', '%d', '%d', '%s', '%s')";
new query[sizeof(fmt_query)+(-2+MAX_PLAYER_NAME)+(-2+64)+(-2+10)+(-2+64)+(-2+8)+(-2+1)+(-2+1)+(-2+2)+(-2+3)+(-2+12)+(-2+15)];
format(query, sizeof(query), fmt_query, player_info[playerid][NAME], player_info[playerid][PASSWORD], player_info[playerid][SALT], player_info[playerid][EMAIL], player_info[playerid][REF], player_info[playerid][SEX], player_info[playerid][RACE], player_info[playerid][AGE], player_info[playerid][SKIN], date, ip);
mysql_query(dbHandle, query);//Пишет что ошибка тут

И так же скидываешь ошибки. А вообще, ты делаешь мод как я вижу по урокам Леона, я знаю его код и твой код 1 в 1 с ним. Ты внимательнее у него посмотри как он сделал. У него нормальный и рабочий код.

Edited by Kutuzov

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now

  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • tamikmod
      By tamikmod
      проблема на фото указана, прошу помочь
       

    • krasin
      By krasin
      Готов приобрести готовый проект в сфере samp/crmp.
       
      Бюджет свободный, предлагайте свои варианты.
    • Jose
      By Jose
      Добрый день, хочу рассказать про хостинг игровых серверов https://hostfy.ru
       
      • Игровой сервер в один клик!
      • Панель управления сервером;
      • Базу данных MySQL
      • Системы управления банами: AmxBans, СS:Bans, SourceBans;
      • Системы статистики сервера: CsStats, AStats;
      • Надежную защиту от DDOS-атак;
      • Пополнение баланса без комиссии! 0%
      • CS GO
      • CS 1.6
      • CS: Source
      • CS: Source v34
      • GTA: SAMP
      • GTA: CRMP
      • GTA: RAGE MP
      • Minecraft
       
      У нас Вы можете заказать хостинг игровых серверов множества игр, по самым адекватным ценам в интернете.
       
       
       
    • Groos
      By Groos

      Качественный игровой хостинг серверов SAMP, CRMP, MTA
       
       
      О нашем хостинге
      - SafePlay - Наш хостинг богат инструментами и различными дополнениями для управления серверами, готовыми сборками модов для автоматической установки серверов SAMP, Нашей панелью управления справиться как и профи, так и новичок. Наши отличные и отзывчивые специалисты(администрация) рады помочь Вам в любую трудную минуту (в том числе по игровой сборке мода,  UCP-сайта или Форумом). Наш хостинг использует надежное и качественное оборудование. Минимальным ping по всей России. Открытая характеристика и статистика хостинга.
        Что мы предлагаем?        - На нашем проекте SafePlay Вы можете создать сервер по справедливым ценам:
      SAMP (LITE) - 0,50 руб/ слот SAMP (VIP) - 1 руб/ слот CRMP - 1 руб / слот MTA - 1 руб / слот
        Ритуал открытия
      - Официальное открытие нашего игрового хостинга: 01.08.2021! В связи с этим, на нашем хостинге присутствует(временная функция) тестирование игрового хостинга (с периодом 15 дней). Для того чтобы активировать данный сервер, Вам достаточно пройти процедуру регистрации >> в разделе "Сервера" >> Заказать сервер "San Andreas: Multiplayers" (за 1 рубль, который вам выдается при регистрации аккаунта). 
        Выслушаем всех!
      - В данной теме, хотелось бы прочитать отзывы, критики а так же пожелания независимых экспертов или бета-тестировщиков. Рады будем любому комментарию, заранее спасибо за внимание, команда администрации SafePlay
    • FanVan
      By FanVan

       
      Дешевый хостинг серверов SAMP, CRMP, Minecraft: Java & Bedrock Edition
       
      Помогаем запуститься начинающим проектам без больших вложений.
      Сделаем так, чтобы твои затраты на хостинг уменьшились без потери качества.
       
      Размещаем серверы в Хельсинках, Финляндия на процессоре частотой до 4.8 ГГц и NVMe диске.
      У нас нет красивого сайта, покупка услуг производится через бота в ЛС группы, а управление сервером -- посредством панели Pterodactyl.
      Мы не ограничиваем тебя слотами: все тарифы -- это маленькие компьютеры, ты волен сам устанавливать максимальное количество игроков, без повышения стоимости.
       
      К нам обращаются, когда хостинг начинает съедать большую часть бюджета из-за того, что хостер захотел выпендриться и добавил бесполезный функционал. Но лучше обратиться еще в начале, чтобы уменьшить затраты на хостинг и вложить как можно больше в рекламу.
       
      Никто не идеален, ничто не идеально: мы не можем помочь
      если у тебя высоконагруженный проект если тебе требуется защита от DDOS если тебе нужен пинг -1 если тебе важна автоустановка модов  
      Но ты можешь написать нам в тех. поддержку и, возможно, мы подберем более мощный тариф на отдельном сервере персонально для тебя по цене ниже, чем у других.
       
      Мы стремимся сделать создание сервера доступным каждому. Если остались вопросы или хочешь протестировать оборудование, напиши нам в ЛС группы.