[Sell] Argos CMS / MVC logic less

Преди известно време бях попитан дали рутиранията могат да избегнат ?page=1/?view=2 и т.н., и тогава категорично отказвах, тъй като знаех, че ще трябва играчка и пипане по рутиращия клас.
Днес вече е възможно да се избегнат и с помощта на бота го направихме.
Добавен е нов параметър в рутиранията, ето пример:
Code:
        // Define the route dynamically
        $collection->attachRoute(new PHPRouter\Route('/pages/'.$page_name, [
            '_controller' => 'App\Controllers\CustomPage::CustomPage',
            'methods' => ['POST', 'GET'],
            'parameters' => ['template_file' => $template_file, 'addon_regex' => '(/p/\d+)?'],
        ]));
Става дума за addon_regex параметъра, който ще слухти за добавки с regex правила. В случая става дума за добавка с /p/ или page.
Добавил съм следното htaccess правило:
Code:
RewriteRule ^pages/banlist/p/([0-9]+)$ /pages/banlist?page=$1 [L,QSA]
и така вече от:
Code:
https://argoscms.pw/pages/banlist?page=2
може да го достъпите и от:
Code:
https://argoscms.pw/pages/banlist/p/2
Естествено в момента е хардкоднато, но от екстеншъните в sql.php при sql заявките за нова страница ще добавя нова колона 'regex' и именно от там ще вкарвате regex правилата за страниците генерирани от екстеншъни.
И така вече ще може да избягвате ? query параметъра и вашите линкове ще са идея по-четливи.
Мога да си поиграя и със страницирането, да направя да слухти за /p/ в url, но това не го обещавам. Идеята е страницирането да си остане с ?page=страница, а страници без странициране главно да се правят с regex правила, като pages/server?vew=1 да стане pages/server/view/1, естествено ако си има странициране вътре би трябвало да си работи.
Не съм го тествал обстойно, но във версия 9.0 ще го вкарам като новост и ще пренапиша gmon екстеншъна, който ще търпи още промени и нови функционалности.

Предстоят много нови неща, като повечето екстеншъни ще се сдобият и с админ панели, където е имало пипане в ext.php, за да е по-удобно за вас.
 
Бота подготви и функция, която ще вкарам в системата и ще се ползва от екстеншъните с горната добавка - https://onlinephp.io/c/c29b4
 
Ето и какво ми се върти в главата за gmon екстеншъна:

- aдмин панел от който ще се контролира всичко
- меню с jquery с облак за модовете
- ще се направят проверки ако някой е купил един от буустовете да не може да купува друг
- ще се изведе операционната система на сървъра
- ще се изведе бутон от който ще се виждат настройките на сървъра
- ще се добавят share бутони за социалните мрежи
- ще се изведат последно играни карти в сървърите и търсачка за търсенето им
- ще се добавят флаг икони в търсачката при държавите
- ще се изведе датата на добавяне на сървъра при преглед
- при фаворитите ще се добави странициране
- нов дизайн на таблицата със сървъри
- динамичните банери за сървъра ще са с нов дизайн и смяна на цветове
- on/off за gametracker изображенията за карти, ако е off - локални
 
Време е да опиша разликите във версия 8.8.1fixfree, която ще пусна безплатно и версия 9.0, която ще е платена.
Преди да го направя искам да кажа, че между 8.8.1fixfree и 8.4.3, която вече е пусната безплатно също има не малко разлики и ако сложите 8.8.1fixfree върху нея е възможно някои екстеншъни да не тръгнат.
За това аз ще изискам парична сума за ъпдейти по екстеншъните, като тя ще е делена на 2 на сумата която сте закупили екстеншъна. Ако той е бил 20лв. ще трябва да заплатите 10 за промените по кода.

8.8.1fixfree:
- Ще бъде добавена функцията get_user_id_by_username($username), чрез която ще се взима юзър айдито по име на потребител
- Ще се добави функцията is_online($user_id) с която ще проверявате дали някой е на линия
- Ще бъде добавена нова функция get_user_ip(), която ще прихваща потребителското айпи по няколко метода, включително и под cloudflare.
- Ще бъде добавена функцията ignore_non_utf8($string), която ще премахва специални символи, които не са utf8 валидни
- Ще бъдат добавени функциите add_to_db_config и remove_from_db_config (https://chatgpt.com/share/8994934b-309b-413b-8e64-c303a324afd4) Може да ги ползвате и по екстеншъните.
- Ще бъдат премахнати сесиите в core.php за смяната на стила. С тях е по добре, но не се сменя стила веднага. Бяха сложени с цел да не се прави всеки път заявка към датабазата, но няма да е добре нито за админи, нито за потребители.
- ще сложа новата anonymous статс функция, за която бях писал в предните постове, че си е била бъгава.
- ще премахна migrate.php от екстеншъните и ще сложа нов модел, който ще изпълнява тяхната роля
- Ще се добавят новите ентита (SteamId, Strings, Arrays, Dates, JsonManager) - това са вид helper-и, които може да ползвате по екстеншъните. Бота ги създаде и са много удобни и лесни за използване.
- Ще бъде добавена нова функция request_uri() капсула на $_SERVER['REQUEST_URI']
- Ще бъде добавена нова функция add_event, която ще е капсула на евент диспечера и вече няма да е необходимо да изписвате <style> и <script> при инжектирането им, защото тя ще го прави автоматично според типа на файла, който подавате.
- ще бъдат добавени колоните show и regex в _pages таблицата и ще бъде вкарана новата придобивка в core.php, а именно addon_regex.
- Админските евенти ще пробвам да ги преместя в admin/includes/admin_events.php
- Ще бъде добавена нова функция, а именно - https://chatgpt.com/share/1f9a525b-622a-4ead-bb36-90a888f24f11, която сама ще проверява дали в стиловете има ланг файлове и ще ги вика директно. Ще бъде като метод викнат в BaseController-a.
- Ще бъде добавена и тази функция - https://chatgpt.com/share/25a93137-014d-4262-b55e-addd5de4a53a чрез която по-лесно ще викате евенти в темплейтите от файла _functions.php.
- ще бъде добавена redirect_to($url,$seconds) функция, чрез която ще редиректвате потребителите към определена страница.
- Ще бъде добавена get_user_country($ip) функция, чрез която ще взимате държавата по айпи
- Ще бъде добавена функцията get_user_group($user_id) с цел да взимате групата на потребителя от форума
- Ще бъде добавена и get_user_rank($user_id) за взимане на ранга.
- Ще бъде изключена проверката за версия в ckeditor-a, за да не дава грешки и в някои екстеншъни също (които го ползват).
- Промени в readme папкатa

Това са промените във версията, която ще пусна безплатно. В нея ще е default стила и екстеншъните по-начало.
С нея аз се презапасявам, че занапред от нея и версия 9.0 нататък всичко ще върви без проблеми.

А сега и чейнчлог за версия 9.0:
- Цялото ядро ще бъде обходено от мен и бота с цел оптимизация и премахване на остарял код
- Ще има чисто нов дизайн на инсталатора
- Екстеншъните при бъг в тях няма да навредят на системата при използване на try/catch блок и rollback страница от която ще ги спирате директно при проблем
- при контролера на празниците в евент календара има еднакви дати и ще бъдат премахнати и оставени по важните празници за всяка еднаква дата.
- В админ панела ще бъде добавен js калкулатор
- В админ панела ще бъде добавен лог за активността на потребителите, които са достъпвали дадени страници от него.
- В jquery/js инжекциите ще бъде премахнат head_ready текста в описанието на страницата и заменен с document.ready.
- Ще бъдат добавени броячи на новините и коментарите в админ панела
- Ще бъде сменен fontawesome js kit-a в темите които го ползват, защото стария не работи вече.
- В логовете в админ панела всички айпита ще пренасочват към whois на domaintools за по лесни справки
- В админ панела при отговора на емейли ще бъде добавен quote бутон, за да може да цитирате текста автоматично.
- Ще бъде добавена функция за изкарването на no avatar-ите чрез random flat background color и първата буква от ника.
- Ще може от админ панела да спирате и пускате последните теми от форума
- В конфигурацията ще бъде добавено поле за цвят за мета тага theme color
- ще бъде добавен youtube бутон в ckeditor-a и екстеншъните, които го ползват
- Custom страниците ще могат да се спират и пускат от админ панела.
- Oт админ панела ще може да се избира default timezone от селект поле
- Тестовите менюта ще бъдат премахнати от темплейтите и админ панела, а и от ядрото
- functions.php оптимизации
- Добавяне на още поддържани игри в greyfish
- Всички екстеншъни ще претърпят оптимизации
- voice captcha при клик на бутон до нея
- прилагане на фикс за обновяването на captch-та под файърфокс
- От админ панела ще решавате дали captcha-та да е само с числа.
- Фикс за ajax чата да вади съобщения само при последно различно chat id съобщение

Ами т'ва е...
 
Last edited:
В търсене съм на нов тестови хостинг за демото. Писах си с namecheap и ми казаха, че не поддържат redis на споделените планове. (https://img.onl/jQ8NHe)
Искам да е нещо различно, за да потвърдя, че и там работи системата.
При namecheap .xyz домейните са с голяма промоция и можеби домейна ще е от тях.

Ще ви държа в течение какво съм решил за хостинг.

ПС:
Хоста е намерен https://easyhost.bg/spodelen-hosting
Поддържат redis с ip и порт, nodejs и ffmpeg.
Питах ги дали не са купени от някои от по-големите в бранша, но отрекоха.
Това ще е следващия хост на който аргос 9.0 ще се настани за тестове
Домейна ще е от namecheap.
 
Last edited:
С бота надраскахме един vanilla js плъгин за добро утро, добър ден и добър вечер. Работи с local storage за определен часови диапазон и съобщението се показва само веднъж.
Цена 5 евро

Screenshot-20240822-193941.png
 
Завърших и rollback-a и дори пригодих и try/catch блока за _functions.php в темплейтите.
Ето и как изглеждат двата кода:
Code:
function load_extensions()
{
    global $dbh, $lang_sys, $ext_language, $bb_is_admin;

    $error_ext_name = null;
    $redirect_url = null;

    // Check for URL parameters to prevent infinite redirection loop
    if (str_contains($_SERVER['REQUEST_URI'], 'add_edit_ext.php?error=')) {
        return; // Stop function if we are already on the error page
    }

    $checker = $dbh->query('SELECT ext_name FROM ' . $_SERVER['DB_PREFIX'] . 'ext WHERE ext_active=1');
    if ($checker->rowCount() > 0) {
        while ($row = $checker->fetch(PDO::FETCH_ASSOC)) {
            $ext_name = $row['ext_name'];
            $extPath = __DIR__ . '/../ext/' . $ext_name;
            $corePath = $extPath . '/ext.php';
            $langPath = $extPath . '/lang/' . get_current_language() . '.php';
            $defaultLangPath = $extPath . '/lang/en.php';

            try {
                if (file_exists($corePath)) {
                    require_once $corePath;
                }

                if (file_exists($langPath)) {
                    include $langPath;
                    $lang_sys = array_merge($lang_sys, $ext_language);
                } elseif (file_exists($defaultLangPath)) {
                    include $defaultLangPath;
                    $lang_sys = array_merge($lang_sys, $ext_language);
                }
            } catch (Throwable $e) {
                error_log('Error loading extension ' . $ext_name . ': ' . $e->getMessage());
                if ($bb_is_admin) {
                    $error_ext_name = $ext_name;
                    $redirect_url = url() . '/admin/add_edit_ext.php?error=' . urlencode($error_ext_name);
                    break; // Exit the loop if an exception is caught
                }
            }
        }
    }

    if ($redirect_url !== null) {
        // Redirect to the error page
        header('Location: ' . $redirect_url);
        exit;
    }
}

Code:
function load_theme_functions() {
    global $bb_is_admin;

    // Determine the path to the theme functions file
    $themeFunctionsPath = __DIR__ . '/../template/' . get_style() . '/_functions.php';

    // Check if the file exists
    if (file_exists($themeFunctionsPath)) {
        try {
            require_once $themeFunctionsPath;
        } catch (Throwable $e) {
            if ($bb_is_admin) {
                // Log the error and show an alert for admin users
                error_log('_functions.php error: ' . $e->getMessage());
                echo alert('danger', '_functions.php error!');
            }
        }
    }
}

Преосмислих някои неща и все повече разбирам, че версия 9.0 ще е с цялостно пренаписано ядро (App/ и includes/functions.php)
Също така ще индентна и admin/template/js_libs.html
Дори няма да остане почти никакъв код, който не е докоснат от бота, защото дори в sql заявките обгражда променливите с { }, а не както сме ги писали с ' . $variable .'
Всичко ще бъде със сменена стилистика и оптимизирано.

С горните два кода се застраховаме, че системата никога няма да се счупи пред потребителите, а и при вас и спокойно ще може да вземете действия и да отстраните проблемите спокойно.

Ето и снимки
rollback: https://i.ibb.co/XDSrFLT/Screenshot-20240824-183850.png
След засечен проблемен екстеншън администратора ще бъде редиректнат към страницата с екстеншъни и ще види оградения в различен цвят бъгав екстеншън.

_functions.php error:
https://i.ibb.co/VHsm6zd/Screenshot-20240824-183530.pngТук минуса е, че съобщението излиза над html тага, но не мисля, че е кой знае какъв проблем, тъй като е видимо само от админи. След отстраняването на проблема, съобщението ще се скрие.

Мисля, че се получи супер.
То почти всичко вече е готово, остава само да се сглоби.

Днес ни обявиха, че ще започнем работа от 29, така, че ще гледам да свърша още нещо, за да съм още по-готов с версия 9.0
 
Last edited:
Ако някой е влизал на демото и е видял грешки, то те са от мен, защото търсих вариант да изолирам някак зареждането на екстеншъни да не са в конструкт метода на basecontroller-a, но не успях.
С бота изписахме цели книги, даже ми спряха и чата и ме накараха да платя или да стартирам нов.
Проблемът сега е, че 1 екстеншън е в loop и зарежда всички други.
Ако имаме 3 екстеншъна, то заявките към датабазата ще са 9, защото всеки зарежда всички и това е цикъл.
Сами разбирате, че при повече екстеншъни става грозно.
Опитахме по всякакви начини, със singleton класове, със статични променливи и return, но не става.
Проблемът е в екстеншъните, защото всеки екстеншън наследява basecontroller-a и в конструкт метода вика parent::construct и циклите започват отново и отново, защото пък в бейсконтролера в конструктора му се викат самите екстеншъните и те от своя страна се викат сами.

Много идиотско, но засега ще остане така докато не измисля вариант. При този начин на работа системата ще зарежда горе долу добре при 35-40 нормални екстеншъна. Под нормални имам в предид около 200 до 700 реда код и без ровене в големи таблици, защото таблиците на gmon могат да съберат 40к логове и ровенето в тях е по бавно . Имам в предвид, че такива екстеншъни като него няма как да заредите 35 или 40, защото системата може и да не зареди.
В момента на демото са 74 и заради това леко бавно зарежда.

Със сигурност има вариант да се оправи, но аз все още не го знам. Идеята ми е всичко да си продължи така, но след като заредят всички да се прекъсва някъде функцията, която ги вика.
Ще намеря начин обещавам.
 
Last edited:
Снощи късно вечерта оправих и това нещо, трябвало е променливите да са със self, за да може да ги достъпва само бейсконтролера, а не и екстеншъните.
След това извиках echo 1;, за да видя колко на брой единици ще ми върне и върна толкова, колкото са включените, иначе връщаше стотици.

Ето и кода в бейс контролера:
Първо декларираме променливите :
Code:
private static $initialized = false;

private static $initialized2 = false;

private static $initialized3 = false;

private static $initialized4 = false;

private static $initialized5 = false;

после викаме методите:
Code:
$this->uniqueStats();
$this->initializeExtensions();
$this->initializeExt_langs();
$this->loadThemefuncs();
$this->deleteOldStats();

Самите методи:
Code:
public static function uniqueStats()
{
    if (self::$initialized) {
        return;
    }

    self::$initialized = true;
    unique_statistic(); //@includes/functions.php
}

public static function initializeExtensions()
{
    if (self::$initialized2) {
        return;
    }

    self::$initialized2 = true;
    
    load_extensions(); //@includes/functions.php
}

public static function initializeExt_langs()
{
    if (self::$initialized3) {
        return;
    }
    global $cacher;

    self::$initialized3 = true;
    load_exts_languages($cacher->get('active_exts')); //@includes/functions.php
}

public static function loadThemefuncs()
{
    if (self::$initialized4) {
        return;
    }

    self::$initialized4 = true;
    load_theme_functions(); //@includes/functions.php
}

public static function deleteOldStats()
{
    if (self::$initialized5) {
        return;
    }

    self::$initialized5 = true;
    delete_old_ads(); //@include/functions.php
}

Ето как изглеждат вече функциите, които викат екстеншъните и техните ланг файлове:

ext:
Code:
function load_extensions()
{
    global $dbh, $bb_is_admin, $cacher;

    $error_ext_name = null;

    if (str_contains($_SERVER['REQUEST_URI'], 'add_edit_ext.php?error=')) {
        return;
    }

    $cacheKey = 'active_exts';
    $active_exts = $cacher->get($cacheKey);

    if (!$cacher->has($cacheKey)) {
        $query = 'SELECT ext_name FROM ' . $_SERVER['DB_PREFIX'] . 'ext WHERE ext_active=1';
        try {
            $checker = $dbh->query($query);
            if ($checker === false) {
                throw new Exception('Database query failed.');
            }

            $active_exts = [];
            while ($row = $checker->fetch(PDO::FETCH_ASSOC)) {
                $active_exts[] = $row['ext_name'];
            }

            $cacher->set($cacheKey, $active_exts, 3600);
        } catch (Throwable $e) {
            error_log('Error querying database for active extensions: ' . $e->getMessage());
            return;
        }
    }

    foreach ($active_exts as $ext_name) {
        $extPath = __DIR__ . '/../ext/' . $ext_name;
        $corePath = $extPath . '/ext.php';
        try {
            if (file_exists($corePath)) {
                require_once $corePath;
            }
        } catch (Throwable $e) {
            error_log('Error loading core file for extension ' . $ext_name . ': ' . $e->getMessage());
            $error_ext_name = $ext_name;
            break;
        }
    }

    if ($error_ext_name !== null && $bb_is_admin) {
        $redirect_url = url() . '/admin/add_edit_ext.php?error=' . urlencode($error_ext_name);
        header('Location: ' . $redirect_url);
        exit;
    }
}

lang:
Code:
function load_exts_languages(array $active_exts)
{
    global $ext_language, $lang_sys, $bb_is_admin;
    $error_ext_name = null;

    if (str_contains($_SERVER['REQUEST_URI'], 'add_edit_ext.php?error=')) {
        return;
    }

    foreach ($active_exts as $ext_name) {
        $extPath = __DIR__ . '/../ext/' . $ext_name;
        $langPath = $extPath . '/lang/' . get_current_language() . '.php';
        $defaultLangPath = $extPath . '/lang/en.php';

        try {
            if (file_exists($langPath)) {
                require_once $langPath;
                $lang_sys = array_merge($lang_sys, $ext_language);
            } elseif (file_exists($defaultLangPath)) {
                require_once $defaultLangPath;
                $lang_sys = array_merge($lang_sys, $ext_language);
            }
        } catch (Exception $e) {
            error_log('Error loading language file for extension ' . $ext_name . ': ' . $e->getMessage());
            $error_ext_name = $ext_name;
            break;
        }
    }

    if ($error_ext_name !== null && $bb_is_admin) {
        $redirect_url = url() . '/admin/add_edit_ext.php?error=' . urlencode($error_ext_name);
        header('Location: ' . $redirect_url);
        exit;
    }
}

Разделих ги на 2 и кеширах активните, за да пренасям информация, понеже като 2та кода са заедно, не успява докрай да извика ланг файловете и за това ги разделих на 2. Вместо throwable ползвам exception в долната функция, защото реално само warnings могат да се появят в ланг файловете, а не грешки.

Аз съм с много бавен нет в момента, върти се около 2 до 4 мб/s и ми зарежда бавно демото, не знам при вас как е, някой може да влезе и провери.
Би трябвало да е идея по-бързо зареждането.
 
Last edited:
Във версия 9.0 всички екстеншъни ще четат файла ext_handler.php, който ще изпълнява код при пускане и спиране на екстеншъните. В комбинация с него ще има и 2 функции, които ще добавя, а именно add_env('key','value') и remove_env('key'), естествено вътре в него може да си добавяте всякакъв код.
Тези 2 функции ще добавят и премахват ключове към config.env файла. Така после може да ги взимате през $_SERVER дефиницията в самия екстеншън.

Това е много полезно.
Ето и съдържанието на ext_handler.php:
Code:
<?php
class ext_handler
{
    public function handle($status)
    {
        if ($status == '1') {
            $this->on();
        } elseif ($status == '0') {
            $this->off();
        }
    }

    protected function on()
    {
        add_env('my_ext',1);
    }

    protected function off()
    {
        remove_env('my_ext');
    }
}

и двете функции:
Code:
// Function to get the path to the config.env file
function get_env_file_path()
{
    // Path to the config.env file in the public_html directory
    return 'config.env';
}

function add_env($key, $val)
{
    $envFile = get_env_file_path();

    // Ensure the file exists
    if (!file_exists($envFile)) {
        return; // File does not exist
    }

    // Read the content of the config.env file
    $content = file_get_contents($envFile);

    if ($content === false) {
        return; // Failed to read the file
    }

    // Prepare the new content
    if (preg_match("/^\"?$key\"?=.*/m", $content)) {
        // Update existing key
        $content = preg_replace("/^\"?$key\"?=.*/m", "\"$key\"=\"$val\"", $content);
    } else {
        // Add new key-value pair without leading newline
        $content .= "\"$key\"=\"$val\"" . PHP_EOL;
    }

    // Write the updated content back to the config.env file
    file_put_contents($envFile, $content, LOCK_EX);
}


function remove_env($key)
{
    $envFile = get_env_file_path();

    // Ensure the file exists
    if (!file_exists($envFile)) {
        return; // File does not exist
    }

    // Read the content of the config.env file
    $content = file_get_contents($envFile);

    if ($content === false) {
        return; // Failed to read the file
    }

    // Prepare the content by removing the line with the given key
    $content = preg_replace("/^\"?$key\"?=.*/m", '', $content);

    // Remove any empty lines left behind
    $content = preg_replace("/^\s*$(?:\r\n?|\n)/m", '', $content);

    // Write the updated content back to the config.env file
    file_put_contents($envFile, $content, LOCK_EX);
}

а, това ще е в модела за пускане и спиране:
Code:
        $classFile = 'ext/' . $id . '/ext_handler.php';
        if (file_exists($classFile)) {
            include_once $classFile;

            if (class_exists('ext_handler')) {
                $handler = new \ext_handler();
                $handler->handle($status);
            }
        }
 
Last edited:
В същия модел по-горе (Extension_Updater_Model.php) под последния код, който съм дал се слага:
Code:
$this->run_migration($id, $status);

и в същия файл декларираме метода:
Code:
protected function run_migration($id, $status)
{
    require_once 'ext/' . $id . '/sql.php';

    $sql_insert .= "
        INSERT INTO " . $this->argos_db_prefix . "ext (ext_name, ext_active, ext_version) 
        VALUES(?, '1', ?);";
    
    $sql_drop .= "
        DELETE FROM " . $this->argos_db_prefix . "ext 
        WHERE ext_name=?;";
    
    if ($status == 1) {
        $go = $this->db->prepare($sql_insert);
        $go->bindParam(1, $id, PDO::PARAM_STR);
        $go->bindParam(2, $ext_version, PDO::PARAM_STR);
        $go->execute();
    } else if ($status == 0) {
        $go = $this->db->prepare($sql_drop);
        $go->bindParam(1, $id, PDO::PARAM_STR);
        $go->execute();
    } else {
        $go = $this->db->prepare($sql_insert);
        $go->bindParam(1, $id, PDO::PARAM_STR);
        $go->bindParam(2, $ext_version, PDO::PARAM_STR);
        $go->execute();
    }
}

като направим тези стъпки migrate.php в папките на екстеншъните стават ненужни и могат да се изтрият.
 
Готов е и бокса с плаващите бутони с модове за gmon екстеншъна.
Ще седят под новините в бокс или ако сте с BLOG_MODE=1 под всички сървъри.

Демо https://codepen.io/Pok4-the-encoder/pen/eYwLaZJ
Демо със снимка
Бутоните вътре са с готин ефект, даже може още да ги пипна като започна с ъпдейтите.
 
Както бях обещал събрах модове за игрите за gmon екстеншъна и по конкретно за game_modes.json файла.
Ето ги и тях:
Code:
{
  "cs16": {
    "1": "Public",
    "2": "Classic",
    "3": "DeathMatch",
    "4": "DeathRun",
    "5": "GunGame",
    "6": "HNS",
    "7": "KreedZ",
    "8": "SoccerJam",
    "9": "Knife",
    "10": "SuperHero",
    "11": "Surf",
    "12": "Warcraft3",
    "13": "PaintBall",
    "14": "Zombie",
    "15": "ZombiePlague",
    "16": "ClanWar",
    "17": "AWP",
    "18": "Dust2 only",
    "19": "Aim",
    "20": "BaseBuilder",
    "21": "JailBreak",
    "22": "Inferno only",
    "23": "Mirage only",
    "24": "Assault only",
    "25": "Rats only",
    "26": "Other"
  },
  "source": {
    "1": "Dust 2 only",
    "2": "CSDM",
    "3": "Classic",
    "4": "Surf",
    "5": "Zombie",
    "6": "GunGame",
    "7": "Inferno only",
    "8": "AWP",
    "9": "Mini games",
    "10": "Mirage only",
    "11": "Bhop",
    "12": "HNS",
    "13": "SoccerJam",
    "14": "JailBreak",
    "15": "Aim",
    "16": "KreedZ",
    "17": "Other"
  },
  "cscz": {
    "1": "Dust 2 only",
    "2": "CSDM",
    "3": "Classic",
    "4": "Inferno only",
    "5": "Retro",
    "6": "GunGame",
    "7": "Zombie mod",
    "8": "Aim",
    "9": "Office only",
    "10": "Other"
  },
  "csgo": {
    "1": "Nuke only",
    "2": "Inferno only",
    "3": "Mirage only",
    "4": "Zombie",
    "5": "Surf",
    "6": "AWP",
    "7": "CSDM",
    "8": "Competitive",
    "9": "JailBreak",
    "10": "KreedZ",
    "11": "Mix",
    "12": "Dust2 only",
    "13": "BHOP",
    "14": "Mini games",
    "15": "Aim",
    "16": "Other"
  },
  "cs2": {
    "1": "Nuke only",
    "2": "Inferno only",
    "3": "Mirage only",
    "4": "Zombie",
    "5": "Surf",
    "6": "AWP",
    "7": "CSDM",
    "8": "Competitive",
    "9": "JailBreak",
    "10": "KreedZ",
    "11": "Mix",
    "12": "Dust2 only",
    "13": "BHOP",
    "14": "Mini games",
    "15": "Aim",
    "16": "Other"
  },
  "halflife": {
    "1": "Crossfire only",
    "2": "GunGame",
    "3": "Deathmatch",
    "4": "SvenCoop",
    "5": "Ricochet",
    "6": "Classic",
    "7": "Other"
  },
  "halflife2": {
    "1": "Deathmatch",
    "2": "Fun",
    "3": "Coop",
    "4": "Crossfire only",
    "5": "Jump",
    "6": "Surf",
    "7": "Classic",
    "8": "Other"
  },
  "tf2": {
    "1": "Zombie",
    "2": "JailBreak",
    "3": "Deathrun",
    "4": "Minecraft",
    "5": "2Fort only",
    "6": "Fun",
    "7": "Classic",
    "8": "Jump",
    "9": "Trade",
    "10": "Surf",
    "11": "Respawn",
    "12": "Other"
  },
  "samp": {
    "1": "Roleplay",
    "2": "RPG",
    "3": "Survival",
    "4": "Zombie",
    "5": "Deathmatch",
    "6": "Other"
  },
  "minecraft": {
    "1": "Survival",
    "2": "Other"
  },
  "fivem": {
    "1": "Roleplay",
    "2": "Other"
  }
}
 
Остават точно 31 дни до връщането ми в България. Надявам се всичко да върви по план.
Новостите ще са много, а след пренаписването на ядрото и екстеншъните, ще дойде ред на темплейтите.
Планирам да я пусна и в още форуми като реклама, тъкмо и от там мога да получа съвети, идеи и препоръки.
Най-вероятно версия 9.0 ще дойде с опция по време на инсталация да се реши дали кеша да е с файлове или с redis, защото има много хостинг планове (така де фирми), които не го поддържат.

Напомням, че версия 9.0 ще струва 100 лв.
Заплащането става по еконт,спиди,изипей или пейпал.
Мъррррр... :)