<?php

/**
 * phpdg — PHP Documentation Generator
 * Generates HTML documentation from PHP files
 */

const PHPDG_VERSION = '1.0';

// @CONFIG_START - User editable configuration section
// ============================================================================
// USER CONFIGURATION - Modify values below
// ============================================================================

$settings = array (
  'directories' => 
  array (
    0 => './src',
  ),
  'output_dir' => 'output',
  'exclude_dirs' => 
  array (
    0 => 'vendor',
    1 => 'node_modules',
    2 => 'cache',
  ),
  'http_auth' => 
  array (
  ),
  'language' => 'en',
  'available_languages' => 
  array (
    0 => 'en',
    1 => 'sk',
    2 => 'cs',
    3 => 'de',
    4 => 'pl',
    5 => 'pt',
    6 => 'ru',
    7 => 'uk',
    8 => 'hi',
    9 => 'fa',
  ),
);

// @CONFIG_END - Do not edit below this line unless you know what you're doing

/*
  |||||
  |||||                        _   _ _                         _      _
  |||||                       | | | (_)                       | |    | |
  |||||                       | |_| |_  ___    ___ _   _ _ __ | |_   | | ___  ___  _ __   ___  ___
  |||||           \|\||       |  _  | |/ __|  / __| | | | '_ \| __|  | |/ _ \/ _ \| '_ \ / _ \/ __|
  |||||          -' ||||/     | | | | | (__   \__ \ |_| | | | | |_   | |  __/ (_) | | | |  __/\__ \
..|||||..       /7   |||||/   \_| |_/_|\___|  |___/\__,_|_| |_|\__|  |_|\___|\___/|_| |_|\___||___/
 ':::::'       /    |||||||/`-._____________
   ':`        \-' |||||||||                   `-._
                -|||||||||||                   |` -`.
                  ||||||                   \   |   `\\
                   |||||\  \__________...---\_  \    \\
                      |  \  \               | \  |    ``-.__--.
                      |  |\  \             / / | |       ``---'
                    _/  /_/  /          __/ / _| |
                   (,__/(,__/          (,__/ (,__/
*/// ============================================================================
// AUTO-REDIRECT - Show generation UI immediately
// ============================================================================

if (!isset($_GET['ggui']) && !isset($_GET['generate']) && !isset($_GET['action'])) {
    header('Location: ?ggui=1');
    exit;
}/**
 * phpdg — constants (logo SVG + favicon)
 */

// phpDG wordmark — clean SVG from CorelDRAW source, fill:currentColor
const LOGO_SVG = '<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="3279px" height="850px" version="1.1" style="shape-rendering:geometricPrecision; text-rendering:geometricPrecision; image-rendering:optimizeQuality; fill-rule:evenodd; clip-rule:evenodd"
viewBox="0 0 3279 850"
 xmlns:xlink="http://www.w3.org/1999/xlink">
 <g id="Layer_x0020_1">
  <image id="Object_x0020_6" x="0" y="0" width="3279" height="850" xlink:href="data:image/png;base64,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"/>
 </g>
</svg>';

const FAVICON_BASE64 = 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSIyMTMzcHgiIGhlaWdodD0iMjEzM3B4IiB2ZXJzaW9uPSIxLjEiIHN0eWxlPSJzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uOyB0ZXh0LXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb247IGltYWdlLXJlbmRlcmluZzpvcHRpbWl6ZVF1YWxpdHk7IGZpbGwtcnVsZTpldmVub2RkOyBjbGlwLXJ1bGU6ZXZlbm9kZCINCnZpZXdCb3g9IjAgMCAyMTMzIDIxMzMiDQogeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPg0KIDxnIGlkPSJMYXllcl94MDAyMF8xIj4NCiAgPGcgaWQ9Il8yNDQ5NDM3OTM2MTQ0Ij4NCiAgIDxpbWFnZSBpZD0iT2JqZWN0X3gwMDIwXzkiIHg9IjAiIHk9IjI2NyIgd2lkdGg9IjIxMzMiIGhlaWdodD0iMTYwMCIgeGxpbms6aHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFnQUFBQUdBQ0FZQUFBR3NKK29wQUFBQUNYQklXWE1BDQpBQXNTQUFBTEVnSFMzWDc4QUFBSk5rbEVRVlI0bk8zZHNXM2xRQlFFUVJrYkJoZGcva2xTV2Z3eHVpcUNCZkhVbWpPRU8vZDV2Nyt3DQpzMzdBbWcrd2ZzQ2FEN0Ird0pvUHNIN0FtZyt3ZnNDYUQ3Qit3Sm9Qc0g3QW1nK3dmc0NhRDdCK3dKb1BzSDdBbWcrd2ZzQ2FEN0IrDQp3Sm9Qc0g3QW1nK3dmc0NhRDdCK3dKb1BzSDdBbWcrd2ZzQ2FEN0Ird0pvUHNIN0FtZyt3ZnNDYUQ3Qit3Sm9Qc0g3QW1nK3dmc0NhDQpEN0Ird05yeDl3SnhQc0Q2QVdzK3dQb0JhejdBK2dGclBzRDZBV3Mrd1BvQmF6N0ErZ0ZyUHNENkFXcyt3UG9CYXo3QStnRnJQc0Q2DQpBV3Mrd1BvQmF6N0ErZ0ZyUHNENkFXcyt3UG9CYXo3QStnRnJQc0Q2QVdzK3dQb0JhejdBK2dGclBzRDZBV3Mrd1BvQmF6N0ErZ0ZyDQpQc0Q2QVdzK3dQb0JhL20vRjZqTC93VFVPWUE0QnhEbkFPSWNRSndEaUhNQWNRNGd6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnDQp6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnemdIRU9ZQTRCeERuQU9JY1FKd0RpSE1BY1E0Z3pnSEVPWUE0QnhEbkFPSWNRSndEDQppSE1BY1E0Z3pnSEVPWUE0QnhEbkFPSWNRSndEaUhNQWNmNi9nRGdGaUhNQWNRNGd6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnDQp6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnemdIRU9ZQTRCeERuQU9JY1FKd0RpSE1BY1E0Z3pnSEVPWUE0QnhEbkFPSWNRSndEDQppSE1BY1E0Z3pnSEVPWUE0QnhEbkFPSWNRSndEaUhNQWNRNGd6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnemdIRU9ZQTRCeERuDQpBT0ljUUp3RGlITUFjUTRnemdIRU9ZQTRCeERuQU9JY1FKd0RpSE1BY1E0Z3pnSEVPWUE0QnhEbkFPSWNRSndEaUhNQWNRNGd6Z0hFDQpPWUE0QnhEbkFPSWNRSndEaUhNQWNRNGd6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnemdIRU9ZQTRCeERuQU9MT2ZkNXYvUWhnDQp3MjhBQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BDQpDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BDQpDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BDQpDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BDQpDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BDQpDRHYzZWIvMUk0QU5Dd0RDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDem4zZWIvMElBT0MzL0FzQUFJSU1BQUFJTWdBQUlNZ0FBSUFnQXdBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEDQpBQUNDREFBQUNESUFBQ0RJQUFDQUlBTUFBSUlNQUFBSU1nQUFJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBDQpDRElBQUNESUFBQ0FJQU1BQUlJTUFBQUlNZ0FBSU1nQUFJQWdBd0FBZ2d3QUFBZ3lBQUFneUFBQWdDQURBQUNDREFBQUNESUFBQ0RJDQpBQUNBSUFNQUFJSU1BQUFJTWdBQUlNZ0FBSUFnQXdBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEQUFDQ0RBQUFDRElBQUNESUFBQ0FJQU1BDQpBSUlNQUFBSU1nQUFJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBQ0RJQUFDRElBQUNBSUFNQUFJSU1BQUFJDQpNZ0FBSU1nQUFJQWdBd0FBZ2d3QUFBZ3lBQUFneUFBQWdDQURBQUNDREFBQUNESUFBQ0RJQUFDQUlBTUFBSUlNQUFBSU1nQUFJTWdBDQpBSUFnQXdBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEQUFDQ0RBQUFDRElBQUNESUFBQ0FJQU1BQUlJTUFBQUlNZ0FBSU1nQUFJQWdBd0FBDQpnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBQ0RJQUFDRElBQUNBSUFNQUFJSU1BQUFJTWdBQUlNZ0FBSUFnQXdBQWdnd0FBQWd5DQpBQUFneUFBQWdDQURBQUNDREFBQUNESUFBQ0RJQUFDQUlBTUFBSUlNQUFBSU1nQUFJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBDQpnQ0FEQUFDQ0RBQUFDRElBQUNESUFBQ0FJQU1BQUlJTUFBQUlNZ0FBSU1nQUFJQWdBd0FBZ2d3QUFBZ3lBQUFneUFBQWdDQURBQUNDDQpEQUFBQ0RJQUFDRElBQUNBSUFNQUFJSU1BQUFJTWdBQUlNZ0FBSUFnQXdBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEQUFDQ0RBQUFDRElBDQpBQ0RJQUFDQUlBTUFBSUlNQUFBSU1nQUFJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBQ0RJQUFDRElBQUNBDQpJQU1BQUlJTUFBQUlNZ0FBSU1nQUFJQWdBd0FBZ2d3QUFBZ3lBQUFneUFBQWdDQURBQUNDREFBQUNESUFBQ0RJQUFDQUlBTUFBSUlNDQpBQUFJTWdBQUlNZ0FBSUFnQXdBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEQUFDQ0RBQUFDRElBQUNESUFBQ0FJQU1BQUlJTUFBQUlNZ0FBDQpJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBQ0RJQUFDRG9IMFpyRktucnVqUkZBQUFBQUVsRlRrU3VRbUNDDQoiLz4NCiAgIDxpbWFnZSBpZD0iREciIHg9IjIxMiIgeT0iNTcxIiB3aWR0aD0iMTcwNCIgaGVpZ2h0PSI5OTYiIHhsaW5rOmhyZWY9ImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBWmtBQUFEdkNBWUFBQUZYcnBrd0FBQUFDWEJJV1hNQQ0KQUFzU0FBQUxFZ0hTM1g3OEFBQWY5MGxFUVZSNG5PMmRqYlhiTmcrRzBYTTZRTE9CTTBIVENhcE8wSFNDT0JNa25TRHVCRWtuaUR0Qg0KMHdtcVR0QjJnbnFEZG9KOG45OHI4MXJYbG14UklnaUNlcDl6bFB1VGE1b3lCUUlFUVBETHo1OC9TOEc4UFY2SDQvVnA2Z3UrUEY3Lw0KbS9sbXI0L1hmdVpyaDRqdHh4ZER2L3h5UVFjK25pN3c3SGo5TjdPZHVSOW9lTjJURzF0eVEzMytIV3A4QW5OdjVyS054L2ROZFVPRA0KalUvNDIrVHZlK3VHZnJ2NCtmdll4aGN3OXZxN0g4S3RHM3A1NTdWL0hhK3ZiN3p4clpzYTY5aTlEeUw4LzlEckg5NXp5U1AzNGtiag0KYzNpZW9wRVVNb1JQYmVpbW11UFZEdnoreGNEdndDSEJleWFmRlByOExzT1AwSitLNzVuc2hrWS9zZHhvamxBTWx6UHFGSkpiQ2tYQw0KR3lvZER6Y1VNOWtzVXF4Rndoc3FIUTgzRkdWNXA3cWhwVmJDMUtYSlhUUkg2QS9GdGtkSmNVTmpvOU9NL0Y3VjdsdDZReXJMNkNYdg0KTy9lR0d1bVdCMlBNWFlKUHVhbWJIK0t0RzlKY0R0eDY3TUx2djVGdW1RL2djSHcvcFdHTlNXR3BneVF3YXlHWThvYjZuK2dVbGs0Tw0KZzY5UGNVTi95N2lmNEI3bzFPVEg2ZUoxZytDR2ZveHNFS3ZMZXk2dUdENmNycTJjWGN0ajNIdWNYM3haY1BRQm85NUk1em1hOUNndg0KaVR5a0V2eEExSnBuNkpkTFpLZi81a3R1Yk02SHFScHhRT056NUdtcGZzUHI0V1U5NEllVTAvVDNZaE50K0VmdVJCb3VmV0liR1hmQw0KWDRJcDk4T2R2N2wxSTdESW00SGYzdzBFak4zTWxNZGxyRU9ZNnUvZHpCaTNSdlZ1RUdESlkzYlA1b3FONDB4OVBNZmU5MzlMWlNiVg0KMnVXN0JHMm9oa3BpYUJQMHc0WHpZNGdoTTB6VmVaZ2lmanBHc09tZTRIVmtCdUhObEVycE54TTFTNVorTTFId1prcEY4MmFlSldnag0KS2lWRzgyYm01cnZOUnRPeHJzbWdpNnNVbVlrMWZRYTluMW9SQWkyYjdDWnpieWE1aTFXbWowNzBTbk5wWitjUzN2ZlNEekNwUDZsbA0KWnVuU04vRHRuZjhmSk9YTnhJN0lraFhxRDhmcjE4dGZwbG8yTDNudDNJVHduNC9YbS81L3pMbVoySmpNUFc0bHFmYTU5SmpDUC9mMA0KWms1UmdMbHhsakZTM3F3bEtReUMyVS91a3FoR0treDA3QUJhbjhOUXU1UHV1UVFMN2JMek9RZkw2c0djRk9FcVlYQXVTUldhbS9vZQ0KMWd5R0EwR0pnOU5udE9NTDJ5dVJxM3VOSFp5NUh4SU1qaVY3SmxMNDVPY01ESUlQYzRPQ0FKc3BZNU1qSjIwT1M4bGZjdjNoeG41WQ0KU3dZb3llYk5HUVJUZVNOZG5Id3ErUHVENWJRMmRUM1FSek9xRmRCby95QnhDN3FIaEljU2RBNDZIU1Arc1FPME9QSElpaElHQjBEOA0KUzFiV0pwUXlPQ0JHN0hlbkt5Vnp0Z3ZHRWlXWkpRMU9ETzhrL2VBVWg5ZkJXUVVjbklMaDRDeERkVk1QQjZkZ09EZ0Z3OEVwR0srRA0KODR0MUIwN004U2hNMWxNbERjN2tjbmpTN2RSTHpVYWh6VVdVTkRqSjZnN01aT3BHcVd5VU1qaWF6a2xNZ2E4aVg2T0ZxNXoxMkhYQw0KSEYyemxlbURveG1TMk1hK3dHSnd2cEp6YmMwWXNGVitPL005WTNhMVk0REc5bWpPWmRaaVZYTndFSnJlUzVxNS9ISHI4RXdRYW80cA0KT2REUE5aMGJxbDdzUFlnZEhJdVlTNnBwWm02aGlmY3pYcE1FYTUxekM0MjVQMnl3dEF6c1RZNWJsVFk0dWNMRWMvSVhsb0pNOVppMQ0Kbk9uZ2xCQ3Y3L2RCYTZDRzdoUGI0dTRaUlMrL0hIbnhHaG43SERBTnZobjV2ejR4dXhYK3UvRitqNVJjYTZoVVFnMmtRQ3NLdXlvZw0KTlZoemJCSzJXY3ZXajZuU2NvdlpwMXBnWU9Zc0JPZXlwTlphRGxJTVJwLys2UnpZNGZWMjZndHpHd0ZZaFBhVmJiVFZvc1N0aWt5cA0KZUNQblFiK3ZZM1Q3Y3BmK3BrY3JROFJpallQM3ZHa3dXQTlNbjdsVjVPYlNTdWVTc1NMc3NIQnhaa0ZzUmJ5NWxKVGlPM2kvcFExTQ0KUUhOd1NocVV3Tlg5bGpvd1FHTndkb25iUzhtVCt5MTVZRURxd1htWHNDMVZZZ1ptU25hOVJudy8xZUFzbWNKaTRrUWJpZHVkMW1mVw0KVnNJbDF0TFNkVUlPZzJDSU9lOTVrQVNlN0Z4VFdYKzFiN1Z1aUNGVjJIbE9MWmliSllZMVFXZDNFai9mNTVTYUptRmJzeW9QV1NuLw0KM2VuS0lUMU41TjlyREg3MDRGaGJaVk1DUjMyZ3EyS2RvTGNPZkxta21QaVU5Y0RFMW9Zc0xxc3lBdWl0eVM0ZzY0RUJ4UndTcXN4Vw0KSXN6b0VnWUdJRTR6VlJxMmt2Wkk5WUQyTkhhSStlTlNCZ1o2WTZyVUlQQzAxK3RLR1pReU1GcVVIQzI5U2UwRFV4cVRwOHVTQmdhbg0KcGNTWXRsVlQwc0MwMWgwb2laSUdodlRnd0JRS0I2WlFPRENGd29FcEZBN01mQkRSdlRxbElSRXNFTFNBaldiakhKaEM0Y0FVQ2dlbQ0KVURnd2hjS0JLWlNTQnNaYjdDUzJDa2NVSlEzTTNyb0RNNGdOUjdzc091YzVBeVk1SlEwTTZlRnhZR0pxK3J2ZDJsN0t3TVRrbGVYYQ0KbzJsS0tRTlRBdGlEditSb3JhU1VNRENsWkdIQzlPWEFuSWlkbHI1UjZVVWVkakYvYkQwd3NmRU1iV1UrWnpmQlZLTDJBMWtOekVibQ0KNzFPTUpTWnBYV3N0NVdMajBseWRrbXZ2U3VxZGE3T3N5SndEczBUSjU2NzliNzVUV25OZzVsUnhIV083OFBWek42bUcxOGF5T0I4Zw0KWm1Dc3pGcnI3WGY5K3g2cnpmemk5UHRrUllPc3JiSjdwQnlVRkR2WGN0VmxmbEh5d0R4WGFMT0ViWVZUOW1KK1ZlckFhRTVmcUNxbw0KbFE4MmhVYnVQeHhGU295MlRrR3BSOVNuVEZuN2NpcFQ3KzE5U1FPVFU4bkRZdHhKM2tLdDdvNEh0cks2UW1IcUhEb24raDZ0QnFhVQ0KNnJGQXMrYi83SWN1eDhETVBaY2xOeWtINk42QTNOVnhyTzkvVGYvendNTHh6N0UvN0JGVjdQcjB0emYvbnJYOVNRcmdndHFLM2dtTw0KV1B0OU9sMEhwZmVZREdhejFDWHRMY0NIMmtyM29icE5qaWtZbk0zUmlsMzYzN2VuNjVaSERFRUlhSWpZb2w3UlFHaThDd3dJSCtxVQ0KSUc1SkJudXA1RGlLSWpXdjVQcFVWSlV6V0Vwd0FlUm15Sk9aK3RSU2IrekVVZFh3Q0M3UHgwbHl1c2NhaFdhSS9tbXlnZG9YNFZzNQ0Kbnd5MUZzTEpLMkQyUkVtaEdhY3ZSRXVQaEM0SjY0QnVLZlFuU2xTZG5yd1dvdEJNbzU5SDZsVURVVmpHQ1NIVVNaTWpoU2FlSmRtQg0KRmxCWXBoTW14NXRqUzZHWmp3ZmhvY0RNQTUvYjZESE5GSnJsbENnOE83SDNoaUZ1c3BkNUZaMGI2UndWbHk3a25NQko4bElHdkcxYQ0KUXFQOUFDSFl0cFh1aGl3UDdlMWpkZnpkSlloQmFVWG1oeGlka1JmUW5xN3R3UCtsM1B4ekQzeU8rRHlmQ0k1WFRRTlB4d2NaVDJpYg0KbXBlVUdnaU9aZkEwbDhCWVRnNzljZCtJL21aZmZKNFFtc2N4OVNvMDkwQkUrM0pnYzluM0NKN0dKZ21tQUFPcktUQWxCb0FQb3BzRw0KSGZpMTl6N1ZDczBRNGFZM29qODdJVFhwSUhsVHV6WDNiSlZnZHQ0RGZXeEZ6MXpIV0Q1TWhHc1Ntc0JCOHN4T3NMdjNraUdCVUhTVA0KVkQwSVRLQVJQUk1WRStGcWhhWVBIZ2pOaGVXL2t1ZWgwMHF1OUNRd0FaaXBxcWI0Mm9VR2hJV2wxZ2V0V1pvTGFKbUFIZ1VtZ0YyUA0KcTZpaGJZM1dwbWZ0Rkh1TnJSMC9LclNaazlVVW5pOEJMY0hSMWphcDhiQTMzUXdLelRVYUJXcThiZWdpMS93UnZxSFFYQVBIZ0liSg0KMDBqNlE4STF0TmNmOS8vRUJXcHJNZ3JOTU5qaGw5cHR1WlB5Z29ORDVIQ1J1NFpDTTR5RzI3S1VIRG15RUFvTklaRlFhQWlKaEVKRA0KU0NRVUdrSWlvZEFRRWdtRmhsZ1I2ajk3NFhIM0pvV0dXSkJ6eTNJcUhyZXpVMmdJaVlSQ1EwZ2tGQnBDSXFIUUVCSUpoWWFRU0NnMA0KaEVSQ29Sa21kODJ5dFhHcjBHTktWT28rVUdpRzBZZ2h2Rlpva3hoQW9ibG1vOVR1WHFsZGtoa0t6VFhhMVRkVG9ySExNbWZ4ZEpkUQ0KYUo2aVZiajhPNlYyRDBydGtodFFhTTVvRmhCdmxkb2xCbEJvT2pRVENKOHJ0YXRKS1dmdExFSE5PMGVoNlFyNWFkWWxPeWkyRGI0Ug0KbmJONFVCNUtzN0M2TmhwbHVCNVl1OUJvbjFtVFk3YldlckFoaUY2MURRdWdLNURqZ0tlY0R4eGlRQjhWMnNYbjlFeDgxVUpUSDlzMQ0KQ1Exc1hEV1ZmVUh1R1hvdk9rSURjRnpJMzFKK0xlcHM0MXU3MEZnY0NXNWwwbWdWYndkZm45b3U4UWpCbkpQaEE3VUlUU1BkaDJkZA0KYU54NkRhQXBPT0RiWHZzNGpzUHFkQUdFQnpTUFM3eUpsdEJZelBDVy9DTGxGSW5BR3VUZkRPL3pYcDY2NldIQ2JTVzlZMklqWGREWg0KZWtKOHBCWk5ZNG0xZHJrRWkzWnRqVE1FSG1xTFkraXpRNkdaVCtsZUpRdkJxWjJIMkJXRkpwN1NOTXN0ME5lTitFcEMxU0RWQk5JSQ0KaFdZeUpYcU5wbktRN3FISjdtVXFBS1F3SFJLMjF4eXZEeFNhY1R3THloQnZUNWVwNXlrVE9BSlNZL2Z0UTBJdmhlWXBwYTlUVWdCUA0KVkRBeGExdnozTklzeVU2M1c3UFEvQ0I2KzJlODBGK2ZhU2V1YWpIVjNiOFhDczFkWUY3dGhkdU1wM0taSmxPeUVNMnhDRkpOa0o4Zw0KTko2OFFTUWZRN2xtdWRkRE1LbTJrczVrVHZLczE2eHBTSHI2NjZHcERHa3cxM3o1K2ZObjZ6NlF1dWtMVFRQdy8yM3YrK0lGaWxxRw0KTEdVajU4T1p0TlkvTU5IMlVvRFRKZ2hNeVhza1lNY2VyRHRCSG9GdzdDU3ZjK0I3dWZaNC9YTHF4eUZqUHg0RXBnYi9QR2FnVnJwWg0KcVBiWWlnVzc0L1hPdWhNWHZEcGRBZXhZM1d1L2FTMG1XWmlCTGl2SUlCS01kSkZEN2c1VndFWjg1YWg5bFBOdTFkVHBNby9VSWpCag0KdkpHbnVWVmFxUlExVVVOS1RSRDA1SnZpYWhlWVMvb0NWTklHc1JKb2p0ZnYxcDFJVE5nUWwweHcxaVl3ZmZvMjhOclRabXBZeDk0aQ0KQ001aVUyM05BdE1ubUNCck05bDJVdDVpWGhPWWFvc3E1MUJnbmhKTU5zdUNFTG1vWGF1TUVhcm16TkkyRkpoaGtxbndBdG1JTCsrWA0KRnZnTW9pMEtDc3h0OEtIV3RNR3NCZzlZU21CTndEeHJwcjZBQW5PZlVMdkxlM1kzaFdXWXFQR2x3RXdISDZwWGJ4cUY1VDZUaElZQw0KRXdjZU9tK2V0RVlvTEZOcDVZNTVSb0dKSjlydU5hYTJZS1FtTU04d0dZNTZTQ2t3ODhBSDIwcjVRck5XMS9FUzRCMmx3Q2dBb2NFSA0KVzZwNVJtR1p6K2g2aGdLekRKaG5yWlRuQ0dpc08xQUJnNU1oQldZNVdGQ1g1bksyWHJjZy9XUXYzVVJ5aUh4dFdCOXV4YmFDRFNiRA0KYkFMelc0STJ0STRUMTZDa09JMlZ0a3UxZ2V1djA5VmZSMnhGNzJTMmUzMTVrbmVtSlRBdmxkb040Q2EyVWxZZDRWYktNSVZ5VGpTNQ0KamdEY3kxa1ljNjdOcmpTY1Y1TU1raDlxQ0FkMllwdDVDeWZBUm14enozSnFGOHZqREwrU1BBZE1nU2RyR2E4Q004VHVkQUdyS3ZiSQ0KUGJNMHpYSm9seEl5dWNQaFVxMTBFNVVtVDlZeU5RbE1IOHNLOWpjRFg0cnNNcnhIYWRuYmpXU2VIR3NWbUVDbzFwanpRNzBaK0ZKRQ0KMnh3dHhhbHhDU2FvamVocTE3MmN0clBYTGpDQm9IRnlMUmgza21mR3o4Vno2dzdjQVphRTV0aGlLL3NXMzZ4RllBS1lKWE5VcU1kcw0KdjFOK2p6NTd4YmF4Wmprb3RwK0tMT2QrcmsxZ0FOeWdyZWd2RmpIcjVmSmF2YnIvSjdPeFh1REhrT3dncFRIV0tEQ2dFWDJoS1RFRA0KSUJadi9kYzB6VloveW5JamRTUW9hZ2VKU1Vjakt4Y1lvRzMzNXNobTNpbTErMHlwWFcyd0sxWWpsTkFJVDFkK0FBK0dWdFI0TUlFdg0KTVZvT0RLOUYzVlhYalJTWTdzRkFUbFNwWnp0YThMTjFCMHFGQXRPQkJaMldhYllWZjRmVWxyb3B6aHdLekJrdGx5VFMwdmNLN1lLUw0KRDhLcUVnck1HZTFvc1FhTmRRZFdSSXQvS0RDK2FSVGFUTEg1enhwVUswMGRZenZnSHdyTVU3NFRuZTI5RDBFdmhYWTFUTWhXb2MzYw0KYUFTa0g4YVBBdk9VVnFsZExLSzNTbTJucHJYdVFBSTB2SjRIL0VPQnljTmp0cXNETkRSaGJvSkdUeVUwajI1MkNzdzFQOG02RGhtcQ0KRlJVUElnWG1HcVN6VUdESUlCU1lhN3ltaEpBTVVHQUlpWUFDa3c4dDF6TEpDQVZtR0kwMG1VWW9NTzZod0F6VGlxOVN0U1FURkpoOA0KTk9KcmZ6d1pnQUl6VEd2ZEFWSW1GQmhDSXFEQURITlFhSk5yb2dxZ3dBekQ0Q1VaaEFKRFNBUVVHRUlpb01BUUVnRUZocEFJS0RERQ0KQ2dSeE45YWRtQWlLQSs3eERRV0dXT0N0T2c5Q0FqaFhrNlZpQ1psSUl4UVlRdUtnd0JBU0FRV0drQWdvTUlSRVFJRWhKQUlLekRBYQ0KTmEzK1VHaVRaSVlDa3c5bVFGY0FCWWFRQ0Nnd3d6VFdIU0JsUW9ISlIydmRBYkljQ3N3d2pYVUhTSmxRWUliaFFVVmtFQXBNUGxqMQ0KOG96V0FienFVR0NJQlM4enZBZGlhWCttYnBRQ1EwZ0VGSmhyVkU2dUluVkFnYmxtWjkwQlVpNFVtR3MwRnFQTUk2c0VDa3dlUGxsMw0KZ0tTQkF2TVVMZS9OWHFsZGtoa0t6Rk4rVldyWFU2WXlqeGE4QVFYR04zOGZyNjhUdDlsSUhRS3owV2lVQW5ObXA5U3U1b0wvSURvQw0KVThOSmFTcmhBUXJNbVhkSzdlNlUyZ1d0cFBmcXVVeFpHYURSYUpRQzA2R1pxdEU2YmRzNzMybzBTb0hwMEZyc2ExUERXc01WRkJoZA0KZS8xbnhiWTF3V2Z5MXJvVEM5aG9OVXlCRVhtajJMYlhodzZmaWRlK2c3MVd3MnNYR0c5VjVNazBWTll2WU0wQ28yMy8vNmpjZnVEMQ0KOGZxbzBDNCtINCtaMjZwN2JkWXFNTWp0U2gyL3VDUlhMR012T2dLai9mbG9vZXJBV2FQQTdFVS8xdkMzY3Z1NWdNbjZoWFVuSWxDZg0KcE5ZbU1EQXpjc3ljdVUwWmpSU1p3RmI4Skk5cU9uQWVXSlBBMUx6QWg5MytqMUxiTVBmMlNtMm5KTXY0cmtGZzlzZnJWY2Izc3pCaA0KRHNydGwyNmFaWnNNYXhZWXhCSGVaMzVQeTdXTGR1bWlVb1VtcStWUW84Qmc0YWR1eTQ1ZzZZYUZXYWI5OEtCOXVMSDN5dTh6QlpVeQ0KU3Zlb1JXQjJvcGR0UEpYWHh1K2ZpNCtueTFMYldLeEhIN1MzUjRGcHBETzNTa3REMzF0MzRNaXo0L1Z2cHZmQ1F3c1ROS2RXemVYbA0KSEVWTFlHcjJTQTFSaW0yZmV5czBIdDR3MWorSnp0NGZ0R2x0UFR6aVVjT1V4blByRGx3QTRiV1lzTjdKMHdjYm1kcklxR2dqMm1paw0KVzR0WnJVSHZRb0ZaQmg2S2czVW5CaWloMlBjYktmakJud3NGWmo3WXExOXFDbndPajlrcW9jRE1wN0h1d0IxZ0ttcEYvMWNMQlNhZQ0KM0o2aHVSeWtNeG1yTTRzc29jREVBVE9zc2U1RUJEQVoxeTR3MzBqbmFVdXlwcVBBVEFjYndqelc2N0x5bXBVQUpyaWtHd1VwTU5OQQ0KUU5CVHVkZEwxaW8wemVscks5UXdXZkN5WHBuQzJvU21IMHhPcG1Vb01PUEE5cTJ0N3RkYWhPWXk4eUtaZFVDQnVVWXJ4YU1VOERDMQ0Kb2xoWnhaaWhOS1ZVRTk4TENzd1p1R0JMRFVTbXBwRXV1T20xNHVjWTJqbDlEUVdtblAwZHVVR2VWeTBtV2k2cllMVUNnMXlySEdmRg0KZXdCQzB4eXYzNDM3TVplY21lTGZyMGxnMW1SeXhkSks5K0JaYk91ZWkwbGNyR2FCZ1lEZ0F6MFk5OE1USDA1WHlldWJ1Uk5ma2d4dQ0KN3dLRE9BazhJSitFSnhXbkpLeHZRQ3RsZU5SK2tHVmpuQ1NER3dKVHltNUJVaVpONy92Y0JVWlNPMlFXUCt2ZU5Rekp5MXQ1YWc3aA0KKzBiU3BKM0FaSUlHMlNkb1N3MEtERmxDV1BPTXNUbGVYMTM4em5YMnhKZWZQMysyN2dNaGhBeXhrVzdDYlU0L3Z6ajlqQ3ZudWhxKw0Ka3NQcGUwejQvNTErRHBmbnhHeDFhSlVSUW5JQ0JRRmwwWnkrV3Rkcm1jTFhjaTZKRjl2ZnNDMnJQWDA5Sk91VkU0S1NnWS9DdzJCNw0KQXc5WXNITHc5YStCNzEwdmhRa1pZQ09kRXRsS0daRThTNzQ5WGJlQ01nakp0MUpwUkJsS3BvYTAxVks1RkxDNUI5WUVhK2dnWjR1SQ0Ka0JMWUNwWEpVc2FxWC80aUZhUXowVjNtZzJBTjNRTVBaWHU2RG5yZElTc0Z1WGxib2RjakY2L2syakNGd1luRUFUZUtoMHFtTG9ZZQ0KeWtBVlZoSEpDcFRLVG95UDZDRlBHREk0aXk2aFNDV3pIc1lVRUxmZWtjQkd1bWVCS3hWZnZKZnozbWxrd3Uya0lHT1NTb1lNK1lPTA0KdG94SVVwRGh0UmV1Vm1vQjQ5aXZPV0JlZkpGS2hnelJ0NHlBK1lOS2tyS1J6dEtsWXFtZi9wbTBKbkpNSlVPbTBIOVFpMXVPazhucw0KWlg2R0kvRlBYNDZYRm1pYURKVU1pZVZ5T1U3WFd0bHNoRWNIazJ1Q0RLc2ZVa29sUTViU2Q2MVI0WlJEeWZXQVNUa2dVeTNzbFh3dQ0KQ2dsQVZESWtKWDJGby9MQWtydFF1WkM1aEJWdlV0bWxraUZhaEFlV3gvZmtnY3FGcENMSWJwTHpMS2hraURZaFJWcmQ5N3RTTnNLWQ0KQzlFQmJqUnM0dDR1YVlSS2h1UWkrSDZwYk5MQndyWkVtN0NKK3h1WldUT1JTb2JraHNwbU9kaEErYWQxSjhpcXdQT0dVd1ZmeHI2UQ0KU29aWUVaUU5Zelp4N0lWN1hZZ05XRFZEWnFOaU5WUXl4Sm9RczJFMjJuMTRMTWM0djUyK2hwTXJaZVRuUzhKcG00SE42UUowUlE2RA0KNTNDeSs0eEtocFFDZ3Rlemx1TXJZQ1ByRE82anVrUXJYZXpwbnJLWXk5eXptY0lKbjNoZUcxbGZpUjY0enlaVkRmQ2taSktrMHltQg0KQjI1eituNGo1N1BKZzVYRUE1Mm1FWmJqWE5XY1dVdjh4VnMxY0NpODluUmRzcEhPQlh6ck5Nd2FRTXI4WFVYalNjbVV6SkxqbE1ONQ0KNTdpNFBPK0ExYzdxQVhVcm1HeTFzd3c0U0tkaytyRkdmUDkrOEs5OUEwVnowM1ZHSldQUFg2ZHJhRUxkU0plamppWDUycGJqRU1oRw0KMXVzK3EwM0JJSnR3SzM1V0txbjVJR2NacjIzakxKN1RVVThUbFV6WkhLU3JlTHk3K0gydFZ0RWxzN0paS2dBdTFsb1V6T3o5RlJXRA0KRlZ4NHB2ZFNSN1pnS3lOYkVxaGtmTkszaWtEdFNtZHRpdVpmNnc0c2hIdWdwck05WFpCbnp6RWN4SjJ4UXJ0eWdWTEoxRUZmNmRSNg0KMGlFVXpUUFJ5VEFxaWIxMUJ4WkE1VEtmRU1OcHhXK2lFRnlBVjhZZ2xVeDl3RFh4NHZSOWJiNWZXUGcxcjJnd1hsNWRKM1NMcGFHUg0KYm1YejBiWWJzOW5LaGFGRUpWTTNmZDl2SzM0dHBENTlKVm9iSGcwQ3JsN1NzNWZ1T2ZjWWw5c0tsY3hxYVU1ZlcvR3RiT0FHaFBLcw0KTGV2TVk3cTJ5Wm54S3dGS0JxdERiNG9HYzh0R2VsbUVWRExyb3psOWJjV3Zza0hXMlU3cW1lQ1FUZVl0Nk10OVRQcEEwV0Eva2JjVg0KYmlPOTFReVZ6SHBweFBkZWpIY3l2dVBhR3p2ckRrUkNCWk1Qck5wUkRjR1RFYkxwLzBBbHMyNWdLU0ZtMDRyUFZjM3ZVa2NpZ0tjSg0KSkpSL0lmbndWcUxtU2N5VVNvYUFSdnp1dGRtSnY1VkFIMi9ISEhqcmJ5MTRXODA4UWlWREFyQk9zYkw1M2JvamtjQnR0aGUvNVVvYQ0KNnc1RThKMTFCMWJNWHFoa1NBVzA0ak9qWlNjTHp5RTN4RXRSVkJ6RDBGcDNZc1c0M1lORUpVTXV3Y01NaTlYVGlnWWJHSGZpYnpYag0KS1EyYmNSZ3lsU2RWT2Foa3lCRHQ4WG90dm5ZZDc4VGZhc2JUcHRMV3VnUGtZVFhwWWVYN1pOVkZKVVBHMkVzM0NYcnhBMk0xczdYdQ0KUkNSZWxNeFAxaDBnRDNoUU1LRHQvMEFsUTI3aExYVVMvZlhrMXZFeWFkUjZ1QmpSZ1NzWkVvV25IY2VJY1hoU01sNXdHM1N1REd5Qw0KTFgyYndldkxYMURKa0h2QWlrVVJSQStiTmEvcUpoV01GMWNaS1lmTGM2UnVzWkd1WEpFV1RlLzdnM1F1c3NGak9LaGt5QlIyNGlmYg0Kakt1WnRQeG0zUUV5aTROeSs1Tlh0MVF5WkFydDhmcGJmQnlFMWdpVkRDSEZRQ1ZEcHJLWDh2M0J3RXN3blpCVlFDVkRwdEphZHlBQw0KeERzWXJDYWtBS2hreUZROFRkcWFBVTlDU0FSVU1pUUdMenVPc1pKcHJUdEJDS0dTSVhHMDRrUEpiS3c3UUFqcG9KSWhNYlRXSFpqSQ0KeHJvRGhKQU9LaGxDQ0NGcVVNa1FRZ2hSZzBxR3hPQWx3OHhEM0lpUVZVQWxRd2doUkEwcUdVSUlJV3BReVJCQ0NGR0RTb1lRUW9nYQ0KVkRLRUVFTFVvSkloaEt5RlZud2N2dWVkTC9vL1VNa1FRdGJBVzZHQ3lRVk8wMzBaZnFDU0lZUVFvZ2FWRENHRUVEV29aQWdoaEtoQg0KSlVNSUlVUU5LaGxDQ0NGcVVNa1FRZ2hSZzBxR3hQREN1Z01UK2MyNkE0U1FEaW9aUWdnaGFsREpFRUlJVVlOS2hzVFFXSGRnSWw0Tw0KVnlPa2VxaGtTQXhlWWpML1dYZUFFTkpCSlVOaThLSmt1SklocEJDb1pNaFV2anBlWDF0M1lpSmN5WkJMYUhnWVFTVkRwdEpZZHlBQw0KVGlqa2tsYTZFdlJiNlZVSWRnb01QamNWcGFsa3lGUzIxaDJZQ1BmSWtGdnNUNWRuNExiKzA3b1RVNkdTSVZQNTNyb0RFMm10TzBBSQ0KT1VNbFE2Yncxcm9ERWJUV0hTQ0VuS0dTSVZONGI5MkJDQmlQSWFRZ3FHVElQYmJXSFlqZ0Yrc09FRUtlUWlWRDd2SFJ1Z01SN0swNw0KVUNGZVluR2tVS2hreUMwK1dIY2drdGE2QXhIUXJVZFdBWlVNR1FON0NkNVlkeUtDSDYwN1VERkltYVZTSkxPZ2tpRkRZTFBYcjlhZA0KaU1UYnFndGdUNDhIZHhRTURpcVpjbWlzT3hBRGxRd1o0bC9yRGtUeWszVUhab0tKMjRPU2VYZThkdGFkSUk4MDFoMklnVXFHWE9MUg0KWXQxWmQyQW1uajdyUm56RnZHckdnMkh5Q0pVTTZZTkp6MHNSeklEbldFeHIzWUVJc0NHM3RlNEVjYldsNEFFcUdSTDRuM1VIWnVJeA0KRmhOQXRlZy94RWV4UTFqUGpWRFJXT09wK3NZRFZETEVWYkc5Qzc2ejdrQUNQb2tQSlFPZzBMMmNLVlFqVy9IbmFhQ1NXVG1ZTkR5bA0KS2ZmNVdlcXdxdmZpcDJ3UEpqZzhNKzZzNlFwQXhxZW5qZEdQVU1tc2s4M3grc2U2RXd2NFcrcVo2T0F5UXptY1Y5WWRtUWlNRXNUdQ0KOXNiOVdCdmVNajRmb1pKWkg2MzRjYytNMFZoM0lERllIWGhSTWdBV05aVGpKK3VPckFSUFdZaFhVTW1zQjgrdXNUN2ZTSDNISzJNUw0KOGJTYUFkaXNpOHcrejRrWEh2Q2FrUE1JbFV6OXRPSi81Ukw0UVp4YmRUZUErOCtUa2dHSUpUWGkvempqRXZHY2tQTUVLcGs2Z2RCNw0KS3d0ekQxak5OYnRuc0RwRDVZSjMxaDJKQktuTnNMYWZINitEYlZlcUFjKzVxdzJYdDZDU3FRZFlQbnR4bU9JNGdiVzRaWGJTR1FnZQ0KeHhDSkpOanoweGozd3pNMUdvZFVNczZCaThWTCt1dGM0Q0tyZVFWelNTTitNNG5nbHNXcWhzb21qaXFWUzRCS3hnL0lrOTlLL1VxbA0KRDRMOHRjWmd4b0RiRElyVjg2UVRsQTJnRzIyY3F0eGlZMURKbE1sR09vWGkxWFdTZ21kU1h4YlpWREQ1d0VWWWcwRVI5bVBoV0lPdA0KckhkTUF6dnhGM2RiQkpXTUhZMTBjUlI4cmQ2YWlZQ3VsZzdFb0RaU1I5bzV3RFBlZHdPdXhRMEtRM0VuNnpJV244eG5WREx4YktSeg0KWGZWcFRsL3grMURiaVlvam50ZkNuZVI5UWxXRFdoUk5uMHQzSU1vRTdjVzNlM1FqM1dwdFZTdVZlM2hTTXU0M0paRlJVQ2FHaFJlSA0KZ2FJNVNCMnVzMXU4a1dGbGlrMnFyWFRLcHdRRjlFTE9IZ2h2KzVwTThLUmtTSjJzeFcyeUJMak9EdUk3R1dBdXIyVDZaQTVqNWRENw0KK1NDM2t3NDJwNnYvODVyY1dsbWdraUZXSUJETW5lTFRnU0pHcHBibndxYmFmQzFVRXFXQTFkN0R5cE5LaHVTR2dmMzVISTdYRjFKWA0KcVNCU09WUXlKQ2ZjTTVHR1Jyb0FzOHZ6UmNpNm9KSWgybkRsb3NQK2RMWENWYzNhQ1lrenJaVHpMRFJDZHhsUkJpbXB0UndzVmpLTg0KVkZTeGwwU0RvcXE3MC9kRmJuU2xraUdwK1U3cU9CYlpFN0FZRWF1cHVnWVd1ZUtMaTU5YktXZC9YaU9ub3JaVU1pUUZmV3VLMklFTQ0KTkV3OHRSeFFSNFp4bGZaUEpVUG1Rc1ZTTG05UEYxYzJkWEZQNXRvODNaakU0NHFLU29iRXdMSXZ2Z2dyRzhac2ZEUFZvQ3VoSWtLZg0KaDcweVZETGtGZ2plNzZUUWdDS1pUSWpaQUxyUy9PREtMVFpBSTFReTVBSllUSmlFcUZUcUpialNVTXdWRTFncEthK2tZMm5LUHlwcA0KbEJMOGY2aEhTQ1d6WG1xb2Vrdm1BME9pT1gwUGhiT1hjaWFuTlpJcUt4TnRsREtPcURtM3BaS3BIMWcybjA0WFZ5aGtDRHdYL1RweQ0KYXpqVzJ4cHNvTVRuM0NadU4zVjdTM2xCSlZNSG9SdzZyb05sUjBnVmZEaGRBU3FkTk9UWW9GeWFaK0lsbEF3MEtpdVhsZ2xXSVFjNQ0KbjZWUjJnTkUxc0dsMG9HdmZTdE1JTGdIanREK2NQZXYwZ1BYMis4Rzd6dkVCa29HRHd5MDYxYW9iSmJ3MjhEdjJ0NzNCem12TXFncw0KaUdmdy9JWUVnZ0RpT25DNWJXVjl5UVFJMXUrbEhKZDBLMTAyb2VXOER1OEtGT3hqZHRtbHBVSUlJVEZnY3QzTDhENnFqWnhyck9Hcg0KUjJNV2lxVHRYUjRvWWw1blRJWVFvczFCcG0zaXhXcG8wN3Z3ODR2ZS82VmFJUVd2dytGMFFVSCsxZnVlSk9UL0xrdVJ4bXpERWhjQQ0KQUFBQVNVVk9SSzVDWUlJPSIvPg0KICAgPGltYWdlIGlkPSJPYmplY3RfeDAwMjBfNyIgeD0iMCIgeT0iMTg2NiIgd2lkdGg9IjIxMzMiIGhlaWdodD0iMjY3IiB4bGluazpocmVmPSJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQWdBQUFBQkFDQVlBQUFFYnVQOHBBQUFBQ1hCSVdYTUENCkFBc1NBQUFMRWdIUzNYNzhBQUFHSUVsRVFWUjRuTzNkNFphYU1CQ0dZZlljTDJxdnBEZlZpN1psdTdaV0U1Z2hNMGttOHo1L3RrWDgNCmlCcENDRUZ2UHo1LzNyZkVidHY5OSt2LytOaSsvdTRlLzk3LzdvNGV2L0tjMThldlBFZnkrRU50MmZkemJuLy84L2hiKzdkMFdldmoNCmxwbWw5VjZXMzhxUE5IcitaS1RMQnRXcW02cXdyeUcxNE5Kenp2SjdlTjBWdHUxcEYzaDJ0aXpLTG5DMFczd3Y5OWtGU3FRMTVLelcNCnVPMEMza2VCMnB2eCtweXpOMDJpVU5WcnkyLzBBODZxamtVcjNidS84RkJhOXZ5Y2JUdnBCMFJwMkdyL0ZpeXpid1FuYU5nZXkvWWwNCjk2T2F1RzNLZm9Ca3c5S2NEdjZyK0pXR1VkOFBpTElMQ0hlTFB2MEFUWS9Rc011czJ3Vzh6OWJPWHFEMERaTDR6cnVYMnFFWDZmc0INCjJkM2VhbCtwSC9HOFhMcnNMUFBLZGp3eXIyeG5SR2FKZEwyRGRkOFBnclVtUjN1d3ZMTHNhUG5WOWJUcnpxcndBWDc4L25zL2VtL1ANCktzWFdxeFBRcWxlbGFLMm9uVFB2d3ZXT2xyOGZBbXEwNnoydnl5R2diMmFKK0JBZ0NkQ3UxMnZQMHBUcG9UUXkxNXJaeWRkcFR2R0INCjFRNEJVaDRmNE1TSEZaOURBR2NCL3dZUURET2J5MWxpY1JiQU9FQnVheDBDb1BaK05XQzJIdmZFaDRxdW1TVUdod3BhZ09Sa0k0RWoNCkIwZ21Ib2dabGluZGptQzkrVnVBV3RQYXNtN0VRNERIZHJZSUZRQ3U1cThBUFFkM0lod0NqTGRUbmhQMDZrb3p6Rm1BVCtiWmRrbzQNCkJLQkdkakdvMTNqNDZONTFoRXpOZGdUcnJkVUN0SjRGZUdUT2NFamtFSUNhdFNwQTYxbUFSK2JraDBTdUJVUTVDeWpoTE9DYS9lM2cNCkd2Z2Z6QWNBRWt0NUJBRHd4NjNhZDMybzlTMmw2N2FzNTVIWjYvVkV5ZXoxdm1mSmxOSnMyekh6L0VKQXp4R1RIcG1ydlI0eVkyUmENCmI5c29rMU1BSURFYUFBdWE3dnBzbVZHNjFwRXpDK3Q5WFlrWWVUcjNqUWJBd2dKZHdjdnJrbmxwdmVvdTJmbjEwQUFBaVoxZkJkRFENCmRFdXNNMmNiWFkrU0dibHJIU1d6OWJPVWNya0tZRkdBSHBrUnVvSms1c3owMkxZR3B3QUFTbWdBWmhYNXlvSkg1bUtuQUZ3RndMSFINClZ3R2laQVk5QmVBcUFJRGh1QmNnZTJia3J2V01tVklYdXVzZW1kd0xRQ2FaUFRLdHQyMlV5ZmNCQUlreEJnQWtSZ01BSkVZREFDUjINCi9qdkJzNDFhZTJSR0dXSE84QjVGcVVkSHVSSzlNay95NkFFQWlkRUFBSW5aelFNWWZaMDFheWF2WjB5bWR0MVJtU2Q1OUFDQXhHZ0ENCmdNUm9BQ3lNL0NZa2oweXVBdGl0TjJQbUV4b0FJREVhQUNBeEdnQUxFVWFETlpsY0JVaVRTUU1BSkVZREFDUm05N3NBbzc5d2NyYVINCjF0Vkd6VmQ3UFI2WnJlOVJiVjBwcmdJQTBLQUJBQkt6KzJXZzBTUGhFNCswdW1ieWV0YkoxSzVya0VjUEFFaU1CZ0JJakFaZ1ZxdmQNClg5Q1NWOHRjN1NvQTl3SUE2SWtHQUVpTUJtQldvNitxak1xTU1tSy9TQ1lOQUpBWURRQ1FHTDhMVUZzdlN1WnE3MUdVZW5TVUs4RzkNCkFBQkdvd0ZZMEg0YzRDZWZJY0h2QWtUUExLeFgzZm1EdnA0cE03WHJqc284dXdydzQvTW5Cd3NBQUpKaENBQUFnSVRvQUFBQWtCQWQNCkFBQUFFcnFwNWoyWGFPWXRTM05IWmtaNTdTUGZTMDB1NVp3N2MrUjdHU1V6YzkzVTVIcTFuWmEwayt3aWxMT2hqSXdBQUFDUUVCMEENCkFBQVNhdjlOc0FqM1FtYk85Q2lqUjI3bWNwSTVkMmJtdXVtVjYxVldheEhLMlZCR1JnQUFBRWlJRGdBQUFBblJBY0FjdkdZd1cxdXQNCm5GRm1nek83M2k1UGs2bkpEWENIeXRmM3BBY29KM2NCQUFBQU4zUUFNQVYrd1FoV3BPZE8wdnFtR2NmUjFPRW81Y1M2NkFCZ0N1SmgNCnVkRXlsek5JcG5WZDhxcWJVY29aNG00RllhYXE0eE9rdm5NWEFBQUFVQ2wvRmZBdXdnU20zV3JsWEdoaWtHckNqWmNJNVl4UzN3RzgNCkM3ei9NZ0lBTjZyaHRvRTdVWlJ5cXF3Mmd6bkNySFZOcGlZM2F6bEgveTZMTnRjeWo3c0FBQUNBRnpvQWdNYkFzM3JWblJLVERUVlcNClJTaG41c2wxSHJtVFRZUnJ6aDA5S3RnMENYREdIWERHTXBWTTltRjJ5ZlBLalZKT0R4NHptRDFFZUM5M1VjcUpOUVN1YjR3QUFBQ1ENCkVCMEFRR1AwY0o4VTViUXplb0laa3dETk12a3E0UC9SQVFBQUlDRTZBQUFBSkVRSEFOQ0lNdUdIY3RxSk1rRTFjem41S3VCTDZBQUENCkFKQVFIUUFBQUJJcS94YkE2SzlnalBBZCs1cE1UUzR6ZysweU5ia1I2cVpIWnBRWnpLdDk1cHJjMWNxcHliU21IUzZQVUU3dUFnQUENCkFCcDBBQUFBU0tqOXE0QW5tOVZJcG5PZVYyN21jcEk1ZDJibXV1bVZHK0h1ajEyRWNuSVhBQUFBMFBnRnlDM3dVS0NDczd3QUFBQUENClNVVk9SSzVDWUlJPSIvPg0KICAgPGltYWdlIGlkPSJPYmplY3RfeDAwMjBfOCIgeD0iMCIgeT0iMCIgd2lkdGg9IjIxMzMiIGhlaWdodD0iMjY3IiB4bGluazpocmVmPSJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQWdBQUFBQkFDQVlBQUFFYnVQOHBBQUFBQ1hCSVdYTUENCkFBc1NBQUFMRWdIUzNYNzhBQUFCczBsRVFWUjRuTzNjc1kzY1FCUkV3VFhHWmY0ZW82VFB6WUp0dktvSUJzUy9wNVp3MEhudTYvMkYNCm5mVUQxbnlBOVFQV2ZJRDFBOVo4Z1BVRDFvNGRFT2NEckIrdzVnT3NIN0RtQTZ3ZnNKYmZBWFg1bjRBNkJ4RG5BT0ljUUp3RGlITUENCmNRNGd6cjhEeENsQW5BT0ljd0J4RGlET0FjUTVnRGdIRU9jQTRoeEFuQU9JY3dCeERpRE9BY1E1Z0RnSEVPZjNBU0RNbndBUUpnQVENCkpnQVFKZ0FRSmdBUUpnQVFKZ0FRSmdBUUpnQVFKZ0FRSmdBUUpnQVFKZ0FRSmdBUUpnQVE1djhEZ0RBTEFNSUVBTUlFQU1JRUFNSUUNCkFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUUNCkFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUVBTUxPYzEvditoRUF3TGY4RFFBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEQUFDQ0RBQUENCkNESUFBQ0RJQUFDQUlBTUFBSUlNQUFBSU1nQUFJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBQ0RJQUFDREkNCkFBQ0FJQU1BQUlJTUFBQUlNZ0FBSU1nQUFJQWdBd0FBZ2d3QUFBZ3lBQUFneUFBQWdDQURBQUNDREFBQUNESUFBQ0RvRDJzQkZETWcNCnBRL3BBQUFBQUVsRlRrU3VRbUNDIi8+DQogIDwvZz4NCiA8L2c+DQo8L3N2Zz4=';
// ============================================================================
// LANGUAGE DEFINITIONS - 10 languages (removed 'ja', added 'pl', 'pt', 'uk', 'hi', 'fa')
// ============================================================================

$languages = [
    'en' => [
        'name' => 'English',
        'native' => 'English',
        'direction' => 'ltr',
        'flag' => '<svg xmlns="http://www.w3.org/2000/svg" width="30" height="18" viewBox="0 0 640 480"><path fill="#012169" d="M0 0h640v480H0z"/><path fill="#FFF" d="m75 0 244 181L562 0h78v62L400 241l240 178v61h-80L320 301 81 480H0v-60l239-178L0 64V0z"/><path fill="#C8102E" d="m424 281 216 159v40L369 281zm-184 20 6 35L54 480H0zM640 0v3L391 191l2-44L590 0zM0 0l239 176h-60L0 42z"/><path fill="#FFF" d="M241 0v480h160V0zM0 160v160h640V160z"/><path fill="#C8102E" d="M0 193v96h640v-96zM273 0v480h96V0z"/></svg>'
    ],
    'sk' => [
        'name' => 'Slovak',
        'native' => 'Slovenčina',
        'direction' => 'ltr',
        'flag' => '<svg xmlns="http://www.w3.org/2000/svg" width="30" height="18" viewBox="0 0 640 480"><path fill="#ee1c25" d="M0 0h640v480H0z"/><path fill="#0b4ea2" d="M0 0h640v320H0z"/><path fill="#fff" d="M0 0h640v160H0z"/><path fill="#fff" d="M233 370.8c-43-20.7-104.6-61.9-104.6-143.2 0-81.4 4-118.4 4-118.4h201.3s3.9 37 3.9 118.4S276 350 233 370.8"/><path fill="#ee1c25" d="M233 360c-39.5-19-96-56.8-96-131.4s3.6-108.6 3.6-108.6h184.8s3.5 34 3.5 108.6C329 303.3 272.5 341 233 360"/><path fill="#fff" d="M241.4 209c10.7.2 31.6.6 50.1-5.6 0 0-.4 6.7-.4 14.4s.5 14.4.5 14.4c-17-5.7-38.1-5.8-50.2-5.7v41.2h-16.8v-41.2c-12-.1-33.1 0-50.1 5.7 0 0 .5-6.7.5-14.4s-.5-14.4-.5-14.4c18.5 6.2 39.4 5.8 50 5.6v-25.9c-9.7 0-23.7.4-39.6 5.7 0 0 .5-6.6.5-14.4 0-7.7-.5-14.4-.5-14.4 15.9 5.3 29.9 5.8 39.6 5.7-.5-16.4-5.3-37-5.3-37s9.9.7 13.8.7 13.8-.7 13.8-.7-4.8 20.6-5.3 37c9.7.1 23.7-.4 39.6-5.7 0 0-.5 6.7-.5 14.4s.5 14.4.5 14.4a119 119 0 0 0-39.7-5.7v26z"/><path fill="#0b4ea2" d="M233 263.3c-19.9 0-30.5 27.5-30.5 27.5s-6-13-22.2-13c-11 0-19 9.7-24.2 18.8 20 31.7 51.9 51.3 76.9 63.4 25-12 57-31.7 76.9-63.4-5.2-9-13.2-18.8-24.2-18.8-16.2 0-22.2 13-22.2 13S253 263.3 233 263.3"/></svg>'
    ],
    'cs' => [
        'name' => 'Czech',
        'native' => 'Čeština',
        'direction' => 'ltr',
        'flag' => '<svg xmlns="http://www.w3.org/2000/svg" width="30" height="18" viewBox="0 0 640 480"><path fill="#fff" d="M0 0h640v240H0z"/><path fill="#d7141a" d="M0 240h640v240H0z"/><path fill="#11457e" d="M360 240 0 0v480z"/></svg>'
    ],
    'de' => [
        'name' => 'German',
        'native' => 'Deutsch',
        'direction' => 'ltr',
        'flag' => '<svg width="30" height="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><path fill="#ffce00" d="M0 320h640v160H0z"/><path d="M0 0h640v160H0z"/><path fill="#d00" d="M0 160h640v160H0z"/></svg>'
    ],
    'ru' => [
        'name' => 'Russian',
        'native' => 'Русский',
        'direction' => 'ltr',
        'flag' => '<svg width="30" height="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 480"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#fff" d="M0 0h640v480H0z"/><path fill="#0039a6" d="M0 160h640v320H0z"/><path fill="#d52b1e" d="M0 320h640v160H0z"/></g></svg>'
    ],
    'pl' => [
        'name' => 'Polish',
        'native' => 'Polski',
        'direction' => 'ltr',
        'flag' => '<svg xmlns="http://www.w3.org/2000/svg" width="30" height="18" viewBox="0 0 640 480"><g fill-rule="evenodd"><path fill="#fff" d="M640 480H0V0h640z"/><path fill="#dc143c" d="M640 480H0V240h640z"/></g></svg>'
    ],
    'pt' => [
        'name' => 'Portuguese',
        'native' => 'Português',
        'direction' => 'ltr',
        'flag' => '<svg xmlns="http://www.w3.org/2000/svg" width="30" height="18" viewBox="0 0 640 480"><path fill="#060" d="M0 0h640v480H0z"/><path fill="#d80027" d="M256 0h384v480H256z"/><circle cx="256" cy="240" r="96" fill="#ff0"/></svg>'
    ],
    'uk' => [
        'name' => 'Ukrainian',
        'native' => 'Українська',
        'direction' => 'ltr',
        'flag' => '<svg xmlns="http://www.w3.org/2000/svg" width="30" height="18" viewBox="0 0 640 480"><g fill-rule="evenodd" stroke-width="1pt"><path fill="#ffd500" d="M0 0h640v480H0z"/><path fill="#005bbb" d="M0 0h640v240H0z"/></g></svg>'
    ],
    'hi' => [
        'name' => 'Hindi',
        'native' => 'हिन्दी',
        'direction' => 'ltr',
        'flag' => '<svg xmlns="http://www.w3.org/2000/svg" width="30" height="18" viewBox="0 0 640 480"><path fill="#f93" d="M0 0h640v160H0z"/><path fill="#fff" d="M0 160h640v160H0z"/><path fill="#128807" d="M0 320h640v160H0z"/><g transform="translate(320 240)scale(3.2)"><circle r="20" fill="#008"/><circle r="17.5" fill="#fff"/><circle r="3.5" fill="#008"/><g id="d"><g id="c"><g id="b"><g id="a" fill="#008"><circle r=".9" transform="rotate(7.5 -8.8 133.5)"/><path d="M0 17.5L.6 7 0 2l-.6 5L0 17.5z"/></g><use width="100%" height="100%" transform="rotate(15)" xlink:href="#a"/></g><use width="100%" height="100%" transform="rotate(30)" xlink:href="#b"/></g><use width="100%" height="100%" transform="rotate(60)" xlink:href="#c"/></g><use width="100%" height="100%" transform="rotate(120)" xlink:href="#d"/><use width="100%" height="100%" transform="rotate(-120)" xlink:href="#d"/></g></svg>'
    ],
    'fa' => [
        'name' => 'Persian',
        'native' => 'فارسی',
        'direction' => 'rtl',
        'flag' => '<svg xmlns="http://www.w3.org/2000/svg" width="30" height="18" viewBox="0 0 640 480"><path fill="#239f40" d="M0 0h640v160H0z"/><path fill="#fff" d="M0 160h640v160H0z"/><path fill="#da0000" d="M0 320h640v160H0z"/></svg>'
    ],
];// ============================================================================
// LANGUAGE TRANSLATIONS
// ============================================================================

$translations = [
    'en' => [
        'GENERATOR_HOME' => 'Home',
        'GENERATOR_FILES' => 'Files',
        'GENERATOR_CLASSES' => 'Classes',
        'GENERATOR_FUNCTIONS' => 'Functions',
        'GENERATOR_CLASSES_HEADING' => 'Classes',
        'GENERATOR_FUNCTIONS_HEADING' => 'Functions',
        'GENERATOR_PROJECT_STRUCTURE' => 'Project Structure',
        'GENERATOR_PARAMETERS' => 'Parameters',
        'GENERATOR_RETURN' => 'return',
        'GENERATOR_SEARCH_PLACEHOLDER' => 'Search functions...',
        'GENERATOR_CLASS' => 'class',
        'GENERATOR_FUNCTION' => 'function',
        'GENERATOR_PROTECTED_AREA' => 'Protected Area',
        'GENERATOR_AUTH_ENABLED' => 'HTTP authentication enabled',
        'GENERATOR_AUTH_DISABLED' => 'HTTP authentication disabled - public access',
        'GENERATOR_USERS' => 'Users',
        'GENERATOR_VIEW_SOURCE' => 'View Source',
    ],
    'sk' => [
        'GENERATOR_HOME' => 'Domov',
        'GENERATOR_FILES' => 'Súborov',
        'GENERATOR_CLASSES' => 'Tried',
        'GENERATOR_FUNCTIONS' => 'Funkcií',
        'GENERATOR_CLASSES_HEADING' => 'Triedy',
        'GENERATOR_FUNCTIONS_HEADING' => 'Funkcie',
        'GENERATOR_PROJECT_STRUCTURE' => 'Štruktúra projektu',
        'GENERATOR_PARAMETERS' => 'Parametre',
        'GENERATOR_RETURN' => 'návrat',
        'GENERATOR_SEARCH_PLACEHOLDER' => 'Hľadať funkcie...',
        'GENERATOR_CLASS' => 'trieda',
        'GENERATOR_FUNCTION' => 'funkcia',
        'GENERATOR_PROTECTED_AREA' => 'Chránená oblasť',
        'GENERATOR_AUTH_ENABLED' => 'HTTP autentifikácia zapnutá',
        'GENERATOR_AUTH_DISABLED' => 'HTTP autentifikácia vypnutá - verejný prístup',
        'GENERATOR_USERS' => 'Používatelia',
        'GENERATOR_VIEW_SOURCE' => 'Zobraziť kód',
    ],
    'cs' => [
        'GENERATOR_HOME' => 'Domů',
        'GENERATOR_FILES' => 'Souborů',
        'GENERATOR_CLASSES' => 'Tříd',
        'GENERATOR_FUNCTIONS' => 'Funkcí',
        'GENERATOR_CLASSES_HEADING' => 'Třídy',
        'GENERATOR_FUNCTIONS_HEADING' => 'Funkce',
        'GENERATOR_PROJECT_STRUCTURE' => 'Struktura projektu',
        'GENERATOR_PARAMETERS' => 'Parametry',
        'GENERATOR_RETURN' => 'návrat',
        'GENERATOR_SEARCH_PLACEHOLDER' => 'Hledat funkce...',
        'GENERATOR_CLASS' => 'třída',
        'GENERATOR_FUNCTION' => 'funkce',
        'GENERATOR_PROTECTED_AREA' => 'Chráněná oblast',
        'GENERATOR_AUTH_ENABLED' => 'HTTP autentizace zapnuta',
        'GENERATOR_AUTH_DISABLED' => 'HTTP autentizace vypnuta - veřejný přístup',
        'GENERATOR_USERS' => 'Uživatelé',
        'GENERATOR_VIEW_SOURCE' => 'Zobrazit kód',
    ],
    'de' => [
        'GENERATOR_HOME' => 'Startseite',
        'GENERATOR_FILES' => 'Dateien',
        'GENERATOR_CLASSES' => 'Klassen',
        'GENERATOR_FUNCTIONS' => 'Funktionen',
        'GENERATOR_CLASSES_HEADING' => 'Klassen',
        'GENERATOR_FUNCTIONS_HEADING' => 'Funktionen',
        'GENERATOR_PROJECT_STRUCTURE' => 'Projektstruktur',
        'GENERATOR_PARAMETERS' => 'Parameter',
        'GENERATOR_RETURN' => 'Rückgabe',
        'GENERATOR_SEARCH_PLACEHOLDER' => 'Funktionen suchen...',
        'GENERATOR_CLASS' => 'Klasse',
        'GENERATOR_FUNCTION' => 'Funktion',
        'GENERATOR_PROTECTED_AREA' => 'Geschützter Bereich',
        'GENERATOR_AUTH_ENABLED' => 'HTTP-Authentifizierung aktiviert',
        'GENERATOR_AUTH_DISABLED' => 'HTTP-Authentifizierung deaktiviert - öffentlicher Zugang',
        'GENERATOR_USERS' => 'Benutzer',
        'GENERATOR_VIEW_SOURCE' => 'Quellcode anzeigen',
    ],
    'ru' => [
        'GENERATOR_HOME' => 'Главная',
        'GENERATOR_FILES' => 'Файлов',
        'GENERATOR_CLASSES' => 'Классов',
        'GENERATOR_FUNCTIONS' => 'Функций',
        'GENERATOR_CLASSES_HEADING' => 'Классы',
        'GENERATOR_FUNCTIONS_HEADING' => 'Функции',
        'GENERATOR_PROJECT_STRUCTURE' => 'Структура проекта',
        'GENERATOR_PARAMETERS' => 'Параметры',
        'GENERATOR_RETURN' => 'возврат',
        'GENERATOR_SEARCH_PLACEHOLDER' => 'Поиск функций...',
        'GENERATOR_CLASS' => 'класс',
        'GENERATOR_FUNCTION' => 'функция',
        'GENERATOR_PROTECTED_AREA' => 'Защищённая область',
        'GENERATOR_AUTH_ENABLED' => 'HTTP-аутентификация включена',
        'GENERATOR_AUTH_DISABLED' => 'HTTP-аутентификация отключена - публичный доступ',
        'GENERATOR_USERS' => 'Пользователи',
        'GENERATOR_VIEW_SOURCE' => 'Просмотр кода',
    ],
    'pl' => [
        'GENERATOR_HOME' => 'Strona główna',
        'GENERATOR_FILES' => 'Plików',
        'GENERATOR_CLASSES' => 'Klas',
        'GENERATOR_FUNCTIONS' => 'Funkcji',
        'GENERATOR_CLASSES_HEADING' => 'Klasy',
        'GENERATOR_FUNCTIONS_HEADING' => 'Funkcje',
        'GENERATOR_PROJECT_STRUCTURE' => 'Struktura projektu',
        'GENERATOR_PARAMETERS' => 'Parametry',
        'GENERATOR_RETURN' => 'zwrot',
        'GENERATOR_SEARCH_PLACEHOLDER' => 'Szukaj funkcji...',
        'GENERATOR_CLASS' => 'klasa',
        'GENERATOR_FUNCTION' => 'funkcja',
        'GENERATOR_PROTECTED_AREA' => 'Obszar chroniony',
        'GENERATOR_AUTH_ENABLED' => 'Uwierzytelnianie HTTP włączone',
        'GENERATOR_AUTH_DISABLED' => 'Uwierzytelnianie HTTP wyłączone - dostęp publiczny',
        'GENERATOR_USERS' => 'Użytkownicy',
        'GENERATOR_VIEW_SOURCE' => 'Zobacz kod źródłowy',
    ],
    'pt' => [
        'GENERATOR_HOME' => 'Início',
        'GENERATOR_FILES' => 'Arquivos',
        'GENERATOR_CLASSES' => 'Classes',
        'GENERATOR_FUNCTIONS' => 'Funções',
        'GENERATOR_CLASSES_HEADING' => 'Classes',
        'GENERATOR_FUNCTIONS_HEADING' => 'Funções',
        'GENERATOR_PROJECT_STRUCTURE' => 'Estrutura do projeto',
        'GENERATOR_PARAMETERS' => 'Parâmetros',
        'GENERATOR_RETURN' => 'retorno',
        'GENERATOR_SEARCH_PLACEHOLDER' => 'Pesquisar funções...',
        'GENERATOR_CLASS' => 'classe',
        'GENERATOR_FUNCTION' => 'função',
        'GENERATOR_PROTECTED_AREA' => 'Área protegida',
        'GENERATOR_AUTH_ENABLED' => 'Autenticação HTTP ativada',
        'GENERATOR_AUTH_DISABLED' => 'Autenticação HTTP desativada - acesso público',
        'GENERATOR_USERS' => 'Usuários',
        'GENERATOR_VIEW_SOURCE' => 'Ver código fonte',
    ],
    'uk' => [
        'GENERATOR_HOME' => 'Головна',
        'GENERATOR_FILES' => 'Файлів',
        'GENERATOR_CLASSES' => 'Класів',
        'GENERATOR_FUNCTIONS' => 'Функцій',
        'GENERATOR_CLASSES_HEADING' => 'Класи',
        'GENERATOR_FUNCTIONS_HEADING' => 'Функції',
        'GENERATOR_PROJECT_STRUCTURE' => 'Структура проекту',
        'GENERATOR_PARAMETERS' => 'Параметри',
        'GENERATOR_RETURN' => 'повернення',
        'GENERATOR_SEARCH_PLACEHOLDER' => 'Пошук функцій...',
        'GENERATOR_CLASS' => 'клас',
        'GENERATOR_FUNCTION' => 'функція',
        'GENERATOR_PROTECTED_AREA' => 'Захищена область',
        'GENERATOR_AUTH_ENABLED' => 'HTTP-аутентифікацію увімкнено',
        'GENERATOR_AUTH_DISABLED' => 'HTTP-аутентифікацію вимкнено - публічний доступ',
        'GENERATOR_USERS' => 'Користувачі',
        'GENERATOR_VIEW_SOURCE' => 'Переглянути код',
    ],
    'hi' => [
        'GENERATOR_HOME' => 'मुख्य पृष्ठ',
        'GENERATOR_FILES' => 'फ़ाइलें',
        'GENERATOR_CLASSES' => 'क्लासेस',
        'GENERATOR_FUNCTIONS' => 'फ़ंक्शन',
        'GENERATOR_CLASSES_HEADING' => 'क्लासेस',
        'GENERATOR_FUNCTIONS_HEADING' => 'फ़ंक्शन',
        'GENERATOR_PROJECT_STRUCTURE' => 'परियोजना संरचना',
        'GENERATOR_PARAMETERS' => 'पैरामीटर',
        'GENERATOR_RETURN' => 'रिटर्न',
        'GENERATOR_SEARCH_PLACEHOLDER' => 'फ़ंक्शन खोजें...',
        'GENERATOR_CLASS' => 'क्लास',
        'GENERATOR_FUNCTION' => 'फ़ंक्शन',
        'GENERATOR_PROTECTED_AREA' => 'सुरक्षित क्षेत्र',
        'GENERATOR_AUTH_ENABLED' => 'HTTP प्रमाणीकरण सक्षम',
        'GENERATOR_AUTH_DISABLED' => 'HTTP प्रमाणीकरण अक्षम - सार्वजनिक पहुंच',
        'GENERATOR_USERS' => 'उपयोगकर्ता',
        'GENERATOR_VIEW_SOURCE' => 'स्रोत कोड देखें',
    ],
    'fa' => [
        'GENERATOR_HOME' => 'صفحه اصلی',
        'GENERATOR_FILES' => 'فایل‌ها',
        'GENERATOR_CLASSES' => 'کلاس‌ها',
        'GENERATOR_FUNCTIONS' => 'توابع',
        'GENERATOR_CLASSES_HEADING' => 'کلاس‌ها',
        'GENERATOR_FUNCTIONS_HEADING' => 'توابع',
        'GENERATOR_PROJECT_STRUCTURE' => 'ساختار پروژه',
        'GENERATOR_PARAMETERS' => 'پارامترها',
        'GENERATOR_RETURN' => 'بازگشت',
        'GENERATOR_SEARCH_PLACEHOLDER' => 'جستجوی توابع...',
        'GENERATOR_CLASS' => 'کلاس',
        'GENERATOR_FUNCTION' => 'تابع',
        'GENERATOR_PROTECTED_AREA' => 'منطقه محافظت شده',
        'GENERATOR_AUTH_ENABLED' => 'احراز هویت HTTP فعال است',
        'GENERATOR_AUTH_DISABLED' => 'احراز هویت HTTP غیرفعال - دسترسی عمومی',
        'GENERATOR_USERS' => 'کاربران',
        'GENERATOR_VIEW_SOURCE' => 'مشاهده کد منبع',
    ],
];// ============================================================================
// AJAX ENDPOINT - Handle source code requests
// ============================================================================

if (isset($_GET['action']) && $_GET['action'] === 'get_source') {
    header('Content-Type: application/json');

    $fileId = $_GET['file_id'] ?? '';
    $lineStart = (int)($_GET['line_start'] ?? 0);
    $lineEnd = (int)($_GET['line_end'] ?? 0);

    // Load file index from cache
    $outputDir = $settings['output_dir'];
    if (!preg_match('/^(?:[A-Za-z]:[\\/]|\/)/', $outputDir)) {
        $outputDir = dirname(__FILE__) . '/' . $outputDir;
    }
    $indexFile = rtrim($outputDir, '/\\') . '/.file_index.json';
    if (!file_exists($indexFile)) {
        echo json_encode(['error' => 'File index not found. Please regenerate documentation.']);
        exit;
    }

    $fileIndex = json_decode(file_get_contents($indexFile), true);
    if (!isset($fileIndex[$fileId])) {
        echo json_encode(['error' => 'Invalid file ID']);
        exit;
    }

    $realFile = $fileIndex[$fileId];

    // Security: validate file exists and is PHP
    if (!file_exists($realFile) || pathinfo($realFile, PATHINFO_EXTENSION) !== 'php') {
        echo json_encode(['error' => 'File not accessible']);
        exit;
    }

    // Read file and extract lines
    $lines = file($realFile);
    $sourceLines = array_slice($lines, $lineStart - 1, $lineEnd - $lineStart + 1);
    $source = implode('', $sourceLines);

    echo json_encode([
        'success' => true,
        'source' => $source,
        'file' => basename($realFile),
        'lines' => "$lineStart-$lineEnd"
    ]);
    exit;
}


// Get file count
if (isset($_GET['action']) && $_GET['action'] === 'get_file_count') {
    header('Content-Type: application/json');

    // Quick scan - just count files
    $count = 0;
    foreach ($settings['directories'] as $dir) {
        if (is_dir($dir)) {
            $iterator = new RecursiveIteratorIterator(
                new RecursiveDirectoryIterator($dir, RecursiveDirectoryIterator::SKIP_DOTS)
            );
            foreach ($iterator as $file) {
                if ($file->getExtension() === 'php') {
                    // Check exclude dirs
                    $skip = false;
                    foreach ($settings['exclude_dirs'] as $exclude) {
                        if (strpos($file->getPathname(), $exclude) !== false) {
                            $skip = true;
                            break;
                        }
                    }
                    if (!$skip) $count++;
                }
            }
        }
    }

    echo json_encode(['count' => $count]);
    exit;
}// ============================================================================
// DOCUMENTATION GENERATOR - do not edit below unless you know what you're doing
// ============================================================================
if (!function_exists('encodeURIComponent')) {
    function encodeURIComponent($str) {
        return rawurlencode($str);
    }
}/**
 * Module 18: JSON Index Generator
 * Generates file-index.json with all documentation URLs and structure
 */

trait JsonIndexModule
{
    private function generateJsonIndex() {
        $this->output("📄 Generating JSON file index...");

        $index = [
            'generated' => date('Y-m-d H:i:s'),
            'version' => self::VERSION,
            'total_files' => count($this->files),
            'total_classes' => count($this->allClasses),
            'total_functions' => count($this->allFunctions),
            'base_url' => $this->settings['output_dir'],
            'files' => []
        ];

        foreach ($this->documentation as $file => $doc) {
            $relativePath = $this->getRelativePath($file);
            $htmlPath = str_replace('.php', '_php', $relativePath) . '.html';

            $fileData = [
                'name' => basename($file),
                'path' => $relativePath,
                'url' => $htmlPath,
                'classes' => []
            ];

            // Add classes with their methods
            foreach ($doc['classes'] as $class) {
                $classData = [
                    'name' => $class['name'],
                    'methods' => []
                ];

                // Add methods to class
                foreach ($class['methods'] as $method) {
                    $classData['methods'][] = $method['name'];
                }

                $fileData['classes'][] = $classData;
            }

            // Add standalone functions (outside classes)
            $fileData['functions'] = [];
            foreach ($doc['functions'] as $function) {
                $fileData['functions'][] = $function['name'];
            }

            $index['files'][] = $fileData;
        }

        $jsonFile = $this->settings['output_dir'] . '/file-index.json';
        file_put_contents($jsonFile, json_encode($index, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));

        $this->output("   ✓ JSON index saved (" . count($index['files']) . " files)");

        $fileIdIndexFile = $this->settings['output_dir'] . '/.file_index.json';
        file_put_contents($fileIdIndexFile, json_encode($this->fileIndex, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));

        $this->output("   ✓ File ID index saved (" . count($this->fileIndex) . " files)");
    }
}/**
 * Module 08: Scanner
 * Trait containing scanner-related methods for phpDocGenerator
 */

trait ScannerModule
{
    private function findFunctionEnd($tokens, $startIndex)
    {
        $braceCount = 0;
        $foundStart = false;

        for ($i = $startIndex; $i < count($tokens); $i++) {
            if ($tokens[$i] === '{') {
                $braceCount++;
                $foundStart = true;
            } elseif ($tokens[$i] === '}') {
                $braceCount--;
                if ($foundStart && $braceCount === 0) {
                    // Find the line number after closing brace
                    // Look ahead for next token with line info
                    for ($j = $i + 1; $j < count($tokens); $j++) {
                        if (is_array($tokens[$j]) && isset($tokens[$j][2])) {
                            return $tokens[$j][2];
                        }
                    }
                    // Fallback: try to get line from previous token
                    for ($j = $i - 1; $j >= 0; $j--) {
                        if (is_array($tokens[$j]) && isset($tokens[$j][2])) {
                            return $tokens[$j][2] + 1; // Add 1 to include closing brace line
                        }
                    }
                    return 0;
                }
            }
        }

        return 0;
    }

    private function scanDirectories()
    {
        $this->output("📂 Scanning directories...");
        foreach ($this->settings['directories'] as $dir) {
            if (!is_dir($dir)) {
                $this->output("⚠️  Directory does not exist: $dir");
                continue;
            }
            $this->scanDirectory($dir);
        }
        $this->output("   Found " . count($this->files) . " PHP files");
        $this->output("");
    }

    private function scanDirectory($dir)
    {
        $items = scandir($dir);
        foreach ($items as $item) {
            if ($item === '.' || $item === '..') continue;

            $path = $dir . DIRECTORY_SEPARATOR . $item;

            if (is_dir($path)) {
                $skip = false;
                if (!empty($this->settings['exclude_dirs'])) {
                    foreach ($this->settings['exclude_dirs'] as $exclude) {
                        if (strpos($path, $exclude) !== false) {
                            $skip = true;
                            break;
                        }
                    }
                }
                if (!$skip) {
                    $this->scanDirectory($path);
                }
            } elseif (pathinfo($path, PATHINFO_EXTENSION) === 'php') {
                $this->files[] = $path;
            }
        }
    }

}


/**
 * Module 09: Parser
 * Trait containing parser-related methods for phpDocGenerator
 */

trait ParserModule
{
    private function findCommonBasePath()
    {
        $paths = [];
        foreach ($this->settings['directories'] as $dir) {
            $realPath = realpath($dir);
            if ($realPath) {
                $paths[] = $realPath;
            }
        }

        if (empty($paths)) {
            return '';
        }

        $commonPath = $paths[0];
        foreach ($paths as $path) {
            while (strpos($path, $commonPath) !== 0) {
                $commonPath = dirname($commonPath);
            }
        }

        return $commonPath;
    }

    private function parseFiles()
    {
        $this->output("🔍 Analyzing PHP files...");
        $total = count($this->files);
        $i = 0;
        $this->emitProgress('parsing', 0, $total, 'Analyzing PHP files');
        foreach ($this->files as $file) {
            $this->documentation[$file] = $this->parseFile($file);
            $i++;
            if ($this->shouldEmit($i, $total)) {
                $this->emitProgress('parsing', $i, $total, 'Analyzing PHP files');
            }
        }
        $this->emitProgress('parsing', $total, $total, 'Analyzing PHP files');
    }

    private function parseFile($file)
    {
        $content = file_get_contents($file);
        $tokens = token_get_all($content);

        $absoluteFile = realpath($file);

        // Relative path from generator.php for AJAX (works with open_basedir)
        $generatorDir = dirname(__FILE__);
        if (strpos($absoluteFile, $generatorDir) === 0) {
            $relativeFile = substr($absoluteFile, strlen($generatorDir) + 1);
        } else {
            // Fallback: use original relative path
            $relativeFile = $file;
        }

        // Create file ID for AJAX (bypasses WAF path traversal blocks)
        $fileId = md5($absoluteFile);
        $this->fileIndex[$fileId] = $absoluteFile;

        $doc = [
            'file' => $file,
            'classes' => [],
            'functions' => [],
            'constants' => []
        ];

        $currentClass = null;
        $currentComment = null;

        for ($i = 0; $i < count($tokens); $i++) {
            $token = $tokens[$i];

            if (is_array($token) && $token[0] === T_DOC_COMMENT) {
                $currentComment = $this->parseDocBlock($token[1]);
            }

            if (is_array($token) && $token[0] === T_CLASS) {
                // Skip ::class constant expressions (T_CLASS preceded by T_DOUBLE_COLON)
                $prevMeaningful = null;
                for ($j = $i - 1; $j >= 0; $j--) {
                    if (is_array($tokens[$j]) && $tokens[$j][0] === T_WHITESPACE) continue;
                    $prevMeaningful = $tokens[$j];
                    break;
                }
                if (is_array($prevMeaningful) && $prevMeaningful[0] === T_DOUBLE_COLON) {
                    continue;
                }

                $className = $this->getNextToken($tokens, $i, T_STRING);
                if ($className === '') { $currentComment = null; continue; } // anonymous class

                $doc['classes'][$className] = [
                    'name' => $className,
                    'comment' => $currentComment,
                    'methods' => [],
                    'properties' => []
                ];
                $currentClass = $className;
                $this->allClasses[] = ['name' => $className, 'file' => $file];
                $currentComment = null;
            }

            if (is_array($token) && $token[0] === T_FUNCTION) {
                $functionName = $this->getNextToken($tokens, $i, T_STRING);
                $params = $this->extractParameters($tokens, $i);

                // Track function position for source code viewer
                $lineStart = $token[2];
                $lineEnd = $this->findFunctionEnd($tokens, $i);

                $visibility = $currentClass ? $this->findVisibility($tokens, $i) : null;

                $functionData = [
                    'name' => $functionName,
                    'comment' => $currentComment,
                    'parameters' => $params,
                    'visibility' => $visibility,
                    'line_start' => $lineStart,
                    'line_end' => $lineEnd,
                    'file' => $relativeFile,
                    'file_id' => $fileId,
                ];

                if ($currentClass) {
                    $doc['classes'][$currentClass]['methods'][] = $functionData;
                } else {
                    $doc['functions'][] = $functionData;
                    $this->allFunctions[] = ['name' => $functionName, 'file' => $file];
                }
                $currentComment = null;
            }

            if (is_array($token) && $token[0] === T_CONST) {
                $constName = $this->getNextToken($tokens, $i, T_STRING);
                $doc['constants'][] = [
                    'name' => $constName,
                    'comment' => $currentComment
                ];
                $currentComment = null;
            }
        }

        return $doc;
    }

    private function parseDocBlock($comment)
    {
        $lines = explode("\n", $comment);
        $parsed = [
            'description' => '',
            'params' => [],
            'return' => '',
            'tags' => []
        ];

        $description = [];
        foreach ($lines as $line) {
            $line = trim($line, " \t\n\r\0\x0B*/");

            if (preg_match('/@param\s+(\S+)\s+\$(\S+)\s*(.*)/', $line, $matches)) {
                $parsed['params'][] = [
                    'type' => $matches[1],
                    'name' => $matches[2],
                    'description' => $matches[3] ?? ''
                ];
            } elseif (preg_match('/@return\s+(\S+)\s*(.*)/', $line, $matches)) {
                $parsed['return'] = $matches[1] . ' ' . ($matches[2] ?? '');
            } elseif (preg_match('/@(\w+)\s*(.*)/', $line, $matches)) {
                $parsed['tags'][$matches[1]] = $matches[2];
            } elseif (!empty($line)) {
                $description[] = $line;
            }
        }

        $parsed['description'] = implode(' ', $description);
        return $parsed;
    }

    private function getNextToken($tokens, $startIndex, $type)
    {
        for ($i = $startIndex + 1; $i < count($tokens); $i++) {
            if (is_array($tokens[$i]) && $tokens[$i][0] === $type) {
                return $tokens[$i][1];
            }
        }
        return '';
    }

    private function findVisibility($tokens, $functionIndex)
    {
        for ($i = $functionIndex - 1; $i >= 0; $i--) {
            $t = $tokens[$i];
            if (is_array($t)) {
                $type = $t[0];
                if ($type === T_PUBLIC) return 'public';
                if ($type === T_PROTECTED) return 'protected';
                if ($type === T_PRIVATE) return 'private';
                if ($type === T_DOC_COMMENT) break;
                if ($type === T_FUNCTION) break;
                if ($type === T_CLASS) break;
                if ($type === T_WHITESPACE) continue;
                if ($type === T_STATIC) continue;
                if ($type === T_ABSTRACT) continue;
                if ($type === T_FINAL) continue;
            } else {
                if ($t === '{' || $t === '}' || $t === ';') break;
            }
        }
        return 'public';
    }

    private function extractParameters($tokens, $startIndex)
    {
        $params = [];
        $inParams = false;
        $currentParam = '';

        for ($i = $startIndex; $i < count($tokens); $i++) {
            if ($tokens[$i] === '(') {
                $inParams = true;
                continue;
            }
            if ($tokens[$i] === ')') {
                if (!empty($currentParam)) {
                    $params[] = trim($currentParam);
                }
                break;
            }
            if ($inParams) {
                if ($tokens[$i] === ',') {
                    $params[] = trim($currentParam);
                    $currentParam = '';
                } else {
                    $currentParam .= is_array($tokens[$i]) ? $tokens[$i][1] : $tokens[$i];
                }
            }
        }

        return $params;
    }
}


/**
 * Module 10: TreeBuilder
 * Trait containing TreeBuilder-related methods for phpDocGenerator
 */

trait TreeBuilderModule
{
    private function buildFileTree() {
        $this->output("🌳 Building tree structure...");

        foreach ($this->files as $file) {
            $relativePath = $this->getRelativePath($file);

            if ($this->fileExistsInTree($relativePath)) {
                continue;
            }

            $parts = explode('/', $relativePath);

            $current = &$this->fileTree;
            foreach ($parts as $index => $part) {
                if ($index === count($parts) - 1) {
                    if (!isset($current['files'])) {
                        $current['files'] = [];
                    }
                    if (!in_array($part, $current['files'])) {
                        $current['files'][] = $part;
                    }
                } else {
                    if (!isset($current['dirs'][$part])) {
                        $current['dirs'][$part] = ['dirs' => [], 'files' => []];
                    }
                    $current = &$current['dirs'][$part];
                }
            }
        }
    }

    private function fileExistsInTree($relativePath) {
        $parts = explode('/', $relativePath);
        $current = $this->fileTree;

        foreach ($parts as $index => $part) {
            if ($index === count($parts) - 1) {
                return isset($current['files']) && in_array($part, $current['files']);
            } else {
                if (!isset($current['dirs'][$part])) {
                    return false;
                }
                $current = $current['dirs'][$part];
            }
        }

        return false;
    }

    private function getRelativePath($file) {
        $file = realpath($file);

        if ($this->baseDir && $file && strpos($file, $this->baseDir) === 0) {
            return str_replace('\\', '/', substr($file, strlen($this->baseDir) + 1));
        }

        return basename($file);
    }
}


/**
 * Module 11: OutputCreator
 * Trait containing OutputCreator-related methods for phpDocGenerator
 */

trait OutputCreatorModule
{
    private function createOutputStructure() {
        $this->output("📁 Creating directory structure...");

        if (!file_exists($this->settings['output_dir'])) {
            mkdir($this->settings['output_dir'], 0755, true);
        }

        $total = count($this->files);
        $i = 0;
        $this->emitProgress('structure', 0, $total, 'Creating directory structure');
        foreach ($this->files as $file) {
            $relativePath = $this->getRelativePath($file);
            $outputPath = $this->settings['output_dir'] . '/' . dirname($relativePath);

            if (!file_exists($outputPath)) {
                mkdir($outputPath, 0755, true);
            }
            $i++;
            if ($this->shouldEmit($i, $total)) {
                $this->emitProgress('structure', $i, $total, 'Creating directory structure');
            }
        }
        $this->emitProgress('structure', $total, $total, 'Creating directory structure');
    }

    private function generateHTMLFiles() {
        $this->output("📄 Generating HTML files...");

        $total = count($this->documentation);
        $i = 0;
        $this->emitProgress('html', 0, $total, 'Generating HTML files');
        foreach ($this->documentation as $file => $doc) {
            $relativePath = $this->getRelativePath($file);
            $displayPath  = $relativePath;
            // Change .php to _php in filename to avoid .htaccess blocking
            $relativePath = str_replace('.php', '_php', $relativePath);
            $outputFile = $this->settings['output_dir'] . '/' . $relativePath . '.html';

            $html = $this->generateFileHTML($file, $doc, $relativePath, $displayPath);
            file_put_contents($outputFile, $html);
            $i++;
            if ($this->shouldEmit($i, $total)) {
                $this->emitProgress('html', $i, $total, 'Generating HTML files');
            }
        }
        $this->emitProgress('html', $total, $total, 'Generating HTML files');
    }

    private function generateFileHTML($file, $doc, $relativePath, $displayPath = null) {
        $depth = substr_count($relativePath, '/');
        $rootPath = $depth > 0 ? str_repeat('../', $depth) : '';
        $generatorPath = str_repeat('../', $depth + 1) . 'generator.php';

        $breadcrumb = $this->generateBreadcrumb($relativePath, $rootPath);
        $content = $this->generateFileContent($file, $doc, $displayPath ?? $relativePath);

        return $this->getHTMLTemplate(
            basename($file),
            $breadcrumb . $content,
            'file',
            $rootPath,
            $generatorPath,
            $relativePath
        );
    }
}


/**
 * Module 12: HtmlGenerator
 * Trait containing HtmlGenerator-related methods for phpDocGenerator
 */

trait HtmlGeneratorModule
{
    private function generateBreadcrumb($path, $rootPath = '') {
        $parts = explode('/', $path);
        $breadcrumb = '<div class="breadcrumb">';
        $breadcrumb .= '<a href="' . $rootPath . 'index.html">' . $this->lang['GENERATOR_HOME'] . '</a>';

        $currentPath = '';
        foreach ($parts as $index => $part) {
            if ($index === count($parts) - 1) {
                $breadcrumb .= ' <span class="separator">›</span> <span class="current">' . htmlspecialchars($part) . '</span>';
            } else {
                $currentPath .= ($currentPath ? '/' : '') . $part;
                $breadcrumb .= ' <span class="separator">›</span> <a href="' . $rootPath . $currentPath . '/index.html">' . htmlspecialchars($part) . '</a>';
            }
        }

        $breadcrumb .= '</div>';
        return $breadcrumb;
    }

}


/**
 * Module 13: Components
 * Trait containing Components-related methods for phpDocGenerator
 */

trait ComponentsModule
{
    private function generateLanguagePicker()
    {
        $currentLang = $this->settings['language'];
        $currentLangData = $this->languages[$currentLang];

        $html = "<div class='language-picker'>\n";
        $html .= "<div class='lang-current' onclick='toggleLanguagePicker()'>\n";
        $html .= $currentLangData['flag'];
        $html .= "<span class='lang-name'>" . htmlspecialchars($currentLangData['native']) . "</span>\n";
        $html .= "<span class='lang-arrow'>▼</span>\n";
        $html .= "</div>\n";
        $html .= "<div class='lang-dropdown' id='langDropdown' style='display:none;'>\n";

        foreach ($this->settings['available_languages'] as $code) {
            if ($code === $currentLang) continue;
            if (!isset($this->languages[$code])) continue;

            $langData = $this->languages[$code];
            $html .= "<div class='lang-option' onclick='changeLang(\"$code\")'>\n";
            $html .= $langData['flag'];
            $html .= "<span class='lang-name'>" . htmlspecialchars($langData['native']) . "</span>\n";
            $html .= "</div>\n";
        }

        $html .= "</div>\n";
        $html .= "</div>\n";

        return $html;
    }

    private function generateTopBar($rootPath, $title, $currentRelativePath = '')
    {
        $version = self::VERSION;
        $homeHref = htmlspecialchars($rootPath . 'index.html');
        $picker = $this->generateLanguagePicker();

        $html = "<header class='topbar'>\n";
        $html .= "  <div class='topbar-logo'><a href='{$homeHref}' title='phpDG'>" . LOGO_SVG . "</a></div>\n";
        $html .= "  <div class='topbar-actions'>\n";
        $html .= "    <span class='pill pill-version'>v{$version}</span>\n";
        $html .= "    {$picker}\n";
        $html .= "    <div class='theme-switch' id='phpdg-theme-toggle' onclick='phpdgToggleTheme()' title='Toggle theme'><span class='ts-knob'></span><span class='ts-icon ts-sun'><svg width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='12' cy='12' r='5'/><line x1='12' y1='1' x2='12' y2='3'/><line x1='12' y1='21' x2='12' y2='23'/><line x1='4.22' y1='4.22' x2='5.64' y2='5.64'/><line x1='18.36' y1='18.36' x2='19.78' y2='19.78'/><line x1='1' y1='12' x2='3' y2='12'/><line x1='21' y1='12' x2='23' y2='12'/><line x1='4.22' y1='19.78' x2='5.64' y2='18.36'/><line x1='18.36' y1='5.64' x2='19.78' y2='4.22'/></svg></span><span class='ts-icon ts-moon'><svg width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z'/></svg></span></div>\n";
        $html .= "  </div>\n";
        $html .= "</header>\n";
        return $html;
    }

    private function generateSidebarPanels($rootPath, $currentRelativePath)
    {
        $searchPh   = $this->lang['GENERATOR_SEARCH_PLACEHOLDER'] ?? 'Search...';
        $countFiles = count($this->files);
        $countClasses = count($this->allClasses);
        $countFn    = count($this->allFunctions);

        $fileTree = $this->generateSidebarFileTree($this->fileTree, '', $rootPath, $currentRelativePath);

        $html  = "<aside class='sidebar' id='sidebar'>\n";
        $html .= "  <div class='sidebar-search'>\n";
        $html .= "    <div class='sidebar-search-wrap'>\n";
        $html .= "      <svg class='sidebar-search-icon' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><circle cx='11' cy='11' r='8'/><path d='M21 21l-4.35-4.35'/></svg>\n";
        $html .= "      <input type='text' id='sidebarSearch' placeholder='" . htmlspecialchars($searchPh) . "'>\n";
        $html .= "    </div>\n";
        $html .= "  </div>\n";
        $html .= "  <div class='sidebar-search-results' id='sidebarSearchResults' style='display:none;'></div>\n";
        $html .= "  <div class='sidebar-tree' id='sidebarTree'>{$fileTree}</div>\n";
        $html .= "</aside>\n";
        return $html;
    }

    private function generateSidebarFileTree($tree, $path, $rootPath, $currentRelativePath, $forceExpandAll = false)
    {
        $html = "<div class='sb-tree'>\n";

        if (!empty($tree['dirs'])) {
            ksort($tree['dirs']);
            foreach ($tree['dirs'] as $dirName => $subTree) {
                $dirPath = $path === '' ? $dirName : $path . '/' . $dirName;
                $isAncestor = $currentRelativePath !== '' && (strpos($currentRelativePath, $dirPath . '/') === 0);
                $expanded = $forceExpandAll || $isAncestor;
                $expandedClass = $expanded ? ' expanded' : '';
                $childDisplay = $expanded ? 'block' : 'none';
                $count = count($subTree['files'] ?? []) + count($subTree['dirs'] ?? []);

                $html .= "<div class='sb-tree-dir{$expandedClass}' onclick='phpdgToggleSbDir(this, event)'>\n";
                $html .= "  <span class='sb-tree-chevron'><svg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' width='12' height='12'><polyline points='9 18 15 12 9 6'/></svg></span>\n";
                $html .= "  <span class='sb-tree-dir-icon'><svg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' width='12' height='12'><path d='M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z'/></svg></span>\n";
                $html .= "  <span style='flex:1;'>" . htmlspecialchars($dirName) . "</span>\n";
                $html .= "  <span style='font-size:10px;color:#6b7280;'>{$count}</span>\n";
                $html .= "</div>\n";
                $html .= "<div class='sb-tree-children' style='display:{$childDisplay};'>\n";
                $html .= $this->generateSidebarFileTree($subTree, $dirPath, $rootPath, $currentRelativePath, $forceExpandAll);
                $html .= "</div>\n";
            }
        }

        if (!empty($tree['files'])) {
            sort($tree['files']);
            foreach ($tree['files'] as $fileName) {
                $relFilePath = $path === '' ? $fileName : $path . '/' . $fileName;
                $htmlFile = str_replace('.php', '_php', $relFilePath) . '.html';
                $href = $rootPath . htmlspecialchars($htmlFile);
                $isActive = ($relFilePath === $currentRelativePath);
                $activeClass = $isActive ? ' is-active' : '';
                $html .= "<a class='sb-tree-file{$activeClass}' href='{$href}'>\n";
                $html .= "  <span class='sb-tree-file-icon'><svg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='1.6' stroke-linecap='round' stroke-linejoin='round' width='14' height='14'><path d='M13 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V9z'/><path d='M13 2v7h7'/></svg></span>\n";
                $html .= "  <span style='flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;'>" . htmlspecialchars($fileName) . "</span>\n";
                $html .= "</a>\n";
            }
        }

        $html .= "</div>\n";
        return $html;
    }

    private function generateStatusBar($title, $type)
    {
        $version = self::VERSION;
        $countFiles    = count($this->files);
        $countClasses  = count($this->allClasses);
        $countFn       = count($this->allFunctions);
        $statusLabel = $this->lang['GENERATOR_GENERATED'] ?? 'Generated';

        $html  = "<div class='statusbar'>\n";
        $html .= "  <div class='statusbar-left'>\n";
        $html .= "    <span>phpDG v{$version}</span>\n";
        if ($type !== 'main') {
            $html .= "    <span>" . htmlspecialchars($title) . "</span>\n";
        }
        $html .= "    <span class='pill'>{$countFiles} files</span>\n";
        $html .= "    <span class='pill'>{$countClasses} classes</span>\n";
        $html .= "    <span class='pill'>{$countFn} fn</span>\n";
        $html .= "  </div>\n";
        $html .= "  <div class='statusbar-right'>\n";
        $html .= "    <span class='status-dot'></span>\n";
        $html .= "    <span>" . htmlspecialchars($statusLabel) . "</span>\n";
        $html .= "  </div>\n";
        $html .= "</div>\n";
        return $html;
    }

    private function generateStatsCards()
    {
        $countFiles    = count($this->files);
        $countClasses  = count($this->allClasses);
        $countFn       = count($this->allFunctions);
        $filesLabel    = $this->lang['GENERATOR_FILES']     ?? 'Files';
        $classesLabel  = $this->lang['GENERATOR_CLASSES']   ?? 'Classes';
        $fnLabel       = $this->lang['GENERATOR_FUNCTIONS'] ?? 'Functions';

        $html  = "<div class='stats-row'>\n";
        $html .= "  <div class='stat-card'><span class='stat-number'>{$countFiles}</span><span class='stat-label' data-i18n='GENERATOR_FILES'>" . htmlspecialchars($filesLabel) . "</span></div>\n";
        $html .= "  <div class='stat-card'><span class='stat-number'>{$countClasses}</span><span class='stat-label' data-i18n='GENERATOR_CLASSES'>" . htmlspecialchars($classesLabel) . "</span></div>\n";
        $html .= "  <div class='stat-card'><span class='stat-number'>{$countFn}</span><span class='stat-label' data-i18n='GENERATOR_FUNCTIONS'>" . htmlspecialchars($fnLabel) . "</span></div>\n";
        $html .= "</div>\n";
        return $html;
    }
}


/**
 * Module 14: HtmlMethods
 * Trait containing HtmlMethods-related methods for phpDocGenerator
 */

trait HtmlMethodsModule
{
    private function generateFileContent($file, $doc, $relativePath = null) {
        $classCount    = count($doc['classes']);
        $methodCount   = 0;
        foreach ($doc['classes'] as $cls) { $methodCount += count($cls['methods']); }
        $functionCount = count($doc['functions']);

        $html  = "<div class='file-header'>\n";
        $html .= "  <div class='file-header-inner'>\n";
        $html .= "    <h1>" . $this->getFileIcon() . "<span>" . htmlspecialchars(basename($file)) . "</span></h1>\n";
        $displayPath = $relativePath ?? basename($file);
        $html .= "    <div class='file-path'>" . htmlspecialchars($displayPath) . "</div>\n";
        $html .= "    <div style='display:flex;gap:8px;margin-top:12px;flex-wrap:wrap;'>\n";
        if ($classCount > 0)    $html .= "      <span class='badge-vis public'>{$classCount} class</span>\n";
        if ($methodCount > 0)   $html .= "      <span class='badge-vis protected'>{$methodCount} methods</span>\n";
        if ($functionCount > 0) $html .= "      <span class='badge-vis private'>{$functionCount} fn</span>\n";
        $html .= "    </div>\n";
        $html .= "  </div>\n";
        $html .= "</div>\n";

        foreach ($doc['classes'] as $class) {
            $clsId = 'class-' . preg_replace('/[^a-zA-Z0-9_-]/', '', $class['name']);
            $html .= "<div class='class' id='" . htmlspecialchars($clsId) . "'>\n";
            $html .= "<h2><span class='keyword' data-i18n='GENERATOR_CLASS'>" . $this->lang['GENERATOR_CLASS'] . "</span> <span class='class-name'>" . htmlspecialchars($class['name']) . "</span></h2>\n";

            if ($class['comment'] && !empty($class['comment']['description'])) {
                $html .= "<div class='description'>" . htmlspecialchars($class['comment']['description']) . "</div>\n";
            }

            if (!empty($class['methods'])) {
                $html .= "<div class='methods-list'>\n";
                foreach ($class['methods'] as $index => $method) {
                    $html .= $this->generateMethodHTML($method, $index, $class['name']);
                }
                $html .= "</div>\n";
            }

            $html .= "</div>\n";
        }

        foreach ($doc['functions'] as $index => $function) {
            $html .= $this->generateFunctionHTML($function, $index);
        }

        return $html;
    }

    private function generateMethodHTML($method, $index, $className = '') {
        $id = 'method-' . preg_replace('/[^a-zA-Z0-9_-]/', '', $className) . '-' . $index;
        $params = !empty($method['parameters']) ? '(' . htmlspecialchars(implode(', ', $method['parameters'])) . ')' : '()';
        $vis = $method['visibility'] ?? 'public';
        $visClass = in_array($vis, ['public', 'protected', 'private'], true) ? $vis : 'public';

        $html  = "<div class='method-item'>\n";
        $html .= "  <div class='method-header' onclick='toggleMethod(\"$id\")'>\n";
        $html .= "    <span class='vis-dot vis-{$visClass}' aria-label='{$visClass}'></span>\n";
        $html .= "    <span class='function-name'>" . htmlspecialchars($method['name']) . "</span>\n";
        $html .= "    <span class='params-preview'>" . $params . "</span>\n";
        $html .= "    <span class='method-meta'><span class='badge-vis {$visClass}'>{$visClass}</span><span class='toggle-icon' id='icon-{$id}'><svg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round' width='12' height='12'><polyline points='9 18 15 12 9 6'/></svg></span></span>\n";
        $html .= "  </div>\n";

        $html .= "  <div class='method-details' id='{$id}' style='display:none;'>\n";

        if ($method['comment'] && !empty($method['comment']['description'])) {
            $html .= "<div class='description'>" . htmlspecialchars($method['comment']['description']) . "</div>\n";
        }

        if ($method['comment'] && !empty($method['comment']['params'])) {
            $html .= "<div class='parameters'><strong data-i18n='GENERATOR_PARAMETERS'>" . $this->lang['GENERATOR_PARAMETERS'] . "</strong>\n";
            foreach ($method['comment']['params'] as $param) {
                $html .= "<div class='param'><span class='type'>" . htmlspecialchars($param['type']) . "</span> ";
                $html .= "<span class='var'>\$" . htmlspecialchars($param['name']) . "</span>";
                if (!empty($param['description'])) {
                    $html .= " <span class='param-desc'>— " . htmlspecialchars($param['description']) . "</span>";
                }
                $html .= "</div>\n";
            }
            $html .= "</div>\n";
        }

        if ($method['comment'] && !empty($method['comment']['return'])) {
            $html .= "<div class='return'><span class='keyword' data-i18n='GENERATOR_RETURN'>" . $this->lang['GENERATOR_RETURN'] . "</span> " . htmlspecialchars($method['comment']['return']) . "</div>\n";
        }

        if (isset($method['line_start']) && isset($method['line_end']) && isset($method['file_id'])) {
            $fid  = htmlspecialchars($method['file_id']);
            $ls   = $method['line_start']; $le = $method['line_end'];
            $name = htmlspecialchars($method['name']);
            $html .= "<div class='source-view-button'>\n";
            $html .= "<button class='btn-view-source' onclick='viewSource(\"{$fid}\",{$ls},{$le},\"{$name}\")'><span data-i18n='GENERATOR_VIEW_SOURCE'>" . $this->lang['GENERATOR_VIEW_SOURCE'] . "</span></button>\n";
            $html .= "<button class='btn-copy-source' onclick='copySource(\"{$fid}\",{$ls},{$le},this)' title='Copy source'><svg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' width='13' height='13'><rect x='9' y='9' width='13' height='13' rx='2'/><path d='M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1'/></svg> Copy</button>\n";
            $html .= "</div>\n";
        }

        $html .= "  </div>\n";
        $html .= "</div>\n";
        return $html;
    }

    private function generateFunctionHTML($function, $index) {
        $id = 'func-' . $index;
        $params = !empty($function['parameters']) ? '(' . htmlspecialchars(implode(', ', $function['parameters'])) . ')' : '()';

        $html  = "<div class='function'>\n";
        $html .= "  <div class='method-header' onclick='toggleMethod(\"$id\")'>\n";
        $html .= "    <span class='vis-dot' style='background:#0ea5e9;box-shadow:0 0 0 3px rgba(14,165,233,0.18);'></span>\n";
        $html .= "    <span class='function-name'>" . htmlspecialchars($function['name']) . "</span>\n";
        $html .= "    <span class='params-preview'>" . $params . "</span>\n";
        $html .= "    <span class='method-meta'><span class='badge-vis' style='background:rgba(14,165,233,0.15);color:#0ea5e9;'>function</span><span class='toggle-icon' id='icon-{$id}'><svg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round' width='12' height='12'><polyline points='9 18 15 12 9 6'/></svg></span></span>\n";
        $html .= "  </div>\n";

        $html .= "  <div class='method-details' id='{$id}' style='display:none;'>\n";

        if ($function['comment'] && !empty($function['comment']['description'])) {
            $html .= "<div class='description'>" . htmlspecialchars($function['comment']['description']) . "</div>\n";
        }

        if ($function['comment'] && !empty($function['comment']['params'])) {
            $html .= "<div class='parameters'><strong data-i18n='GENERATOR_PARAMETERS'>" . $this->lang['GENERATOR_PARAMETERS'] . "</strong>\n";
            foreach ($function['comment']['params'] as $param) {
                $html .= "<div class='param'><span class='type'>" . htmlspecialchars($param['type']) . "</span> ";
                $html .= "<span class='var'>\$" . htmlspecialchars($param['name']) . "</span>";
                if (!empty($param['description'])) {
                    $html .= " <span class='param-desc'>— " . htmlspecialchars($param['description']) . "</span>";
                }
                $html .= "</div>\n";
            }
            $html .= "</div>\n";
        }

        if ($function['comment'] && !empty($function['comment']['return'])) {
            $html .= "<div class='return'><span class='keyword' data-i18n='GENERATOR_RETURN'>" . $this->lang['GENERATOR_RETURN'] . "</span> " . htmlspecialchars($function['comment']['return']) . "</div>\n";
        }

        if (isset($function['line_start']) && isset($function['line_end']) && isset($function['file_id'])) {
            $fid  = htmlspecialchars($function['file_id']);
            $ls   = $function['line_start']; $le = $function['line_end'];
            $name = htmlspecialchars($function['name']);
            $html .= "<div class='source-view-button'>\n";
            $html .= "<button class='btn-view-source' onclick='viewSource(\"{$fid}\",{$ls},{$le},\"{$name}\")'><span data-i18n='GENERATOR_VIEW_SOURCE'>" . $this->lang['GENERATOR_VIEW_SOURCE'] . "</span></button>\n";
            $html .= "<button class='btn-copy-source' onclick='copySource(\"{$fid}\",{$ls},{$le},this)' title='Copy source'><svg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' width='13' height='13'><rect x='9' y='9' width='13' height='13' rx='2'/><path d='M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1'/></svg> Copy</button>\n";
            $html .= "</div>\n";
        }

        $html .= "  </div>\n";
        $html .= "</div>\n";
        return $html;
    }
}


/**
* Module 15: DirectoryIndexes
* Trait containing DirectoryIndexes-related methods for phpDocGenerator
*/

trait DirectoryIndexesModule
{
private function generateDirectoryIndexes() {
$this->output("📂 Generating directory indexes...");
$this->generateDirIndex($this->fileTree, '');
}

private function generateDirIndex($tree, $path) {
if (!empty($tree['dirs'])) {
foreach ($tree['dirs'] as $dirName => $subTree) {
$dirPath = $path ? $path . '/' . $dirName : $dirName;
$outputFile = $this->settings['output_dir'] . '/' . $dirPath . '/index.html';

$depth = substr_count($dirPath, '/') + 1;
$rootPath = str_repeat('../', $depth);

$breadcrumb = $this->generateBreadcrumb($dirPath, $rootPath);
$treeHtml = $this->generateTreeHTML($subTree);
$content = $breadcrumb . "<div class='directory-index'><h1>" . $this->getFolderIcon() . " " . htmlspecialchars($dirName) . "</h1>" . $treeHtml . "</div>";

$html = $this->getHTMLTemplate($dirName, $content, 'directory', $rootPath, $rootPath . '../generator.php', $dirPath);
file_put_contents($outputFile, $html);

$this->generateDirIndex($subTree, $dirPath);
}
}
}

private function generateTreeHTML($tree) {
$html = "<div class='tree'>\n";

    if (!empty($tree['dirs'])) {
    ksort($tree['dirs']);
    foreach ($tree['dirs'] as $dirName => $subTree) {
    $html .= "<div class='tree-item'>\n";
        $html .= $this->getFolderIcon() . " <a href='" . htmlspecialchars($dirName) . "/index.html'>" . htmlspecialchars($dirName) . "</a>\n";
        $html .= "</div>\n";
    }
    }

    if (!empty($tree['files'])) {
    sort($tree['files']);
    foreach ($tree['files'] as $fileName) {
    $html .= "<div class='tree-item'>\n";
        $fileNameHtml = str_replace('.php', '_php', $fileName);
        $html .= $this->getFileIcon() . " <a href='" . htmlspecialchars($fileNameHtml) . ".html'>" . htmlspecialchars($fileName) . "</a>\n";
        $html .= "</div>\n";
    }
    }

    $html .= "</div>\n";
return $html;
}

private function generateMainIndex() {
$this->output("🏠 Generating main index.html...");

$content = $this->generateStatsCards();

// Classes section
if (!empty($this->allClasses)) {
    $label = $this->lang['GENERATOR_CLASSES_HEADING'] ?? 'Classes';
    $sorted = $this->allClasses;
    usort($sorted, fn($a, $b) => strcmp($a['name'], $b['name']));

    $count = count($sorted);
    $content .= "<section class='index-section'>\n";
    $content .= "<h2 class='index-section-title' onclick='phpdgToggleIndex(this)'>";
    $content .= "<span class='index-chevron'><svg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round' width='13' height='13'><polyline points='9 18 15 12 9 6'/></svg></span>";
    $content .= htmlspecialchars($label);
    $content .= "<span class='index-count'>{$count}</span>";
    $content .= "</h2>\n";
    $content .= "<div class='index-table' style='display:none;'>\n";
    foreach ($sorted as $cls) {
        $relPath  = $this->getRelativePath($cls['file']);
        $htmlPath = str_replace('.php', '_php', $relPath) . '.html';
        $anchor   = '#class-' . preg_replace('/[^a-zA-Z0-9_-]/', '', $cls['name']);
        $dir      = dirname($relPath) !== '.' ? dirname($relPath) . '/' : '';
        $base     = basename($relPath);
        $content .= "<a class='index-row' href='" . htmlspecialchars($htmlPath . $anchor) . "'>";
        $content .= "<span class='index-symbol'>" . htmlspecialchars($cls['name']) . "</span>";
        $content .= "<span class='index-file'><span class='index-file-dir'>" . htmlspecialchars($dir) . "</span>" . htmlspecialchars($base) . "</span>";
        $content .= "</a>\n";
    }
    $content .= "</div>\n</section>\n";
}

// Functions section
if (!empty($this->allFunctions)) {
    $label = $this->lang['GENERATOR_FUNCTIONS_HEADING'] ?? 'Functions';
    $sorted = $this->allFunctions;
    usort($sorted, fn($a, $b) => strcmp($a['name'], $b['name']));

    $count = count($sorted);
    $content .= "<section class='index-section'>\n";
    $content .= "<h2 class='index-section-title' onclick='phpdgToggleIndex(this)'>";
    $content .= "<span class='index-chevron'><svg viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round' width='13' height='13'><polyline points='9 18 15 12 9 6'/></svg></span>";
    $content .= htmlspecialchars($label);
    $content .= "<span class='index-count'>{$count}</span>";
    $content .= "</h2>\n";
    $content .= "<div class='index-table' style='display:none;'>\n";
    foreach ($sorted as $fn) {
        $relPath  = $this->getRelativePath($fn['file']);
        $htmlPath = str_replace('.php', '_php', $relPath) . '.html';
        $dir      = dirname($relPath) !== '.' ? dirname($relPath) . '/' : '';
        $base     = basename($relPath);
        $content .= "<a class='index-row' href='" . htmlspecialchars($htmlPath) . "'>";
        $content .= "<span class='index-symbol'>" . htmlspecialchars($fn['name']) . "</span>";
        $content .= "<span class='index-file'><span class='index-file-dir'>" . htmlspecialchars($dir) . "</span>" . htmlspecialchars($base) . "</span>";
        $content .= "</a>\n";
    }
    $content .= "</div>\n</section>\n";
}

$html = $this->getHTMLTemplate('phpDG', $content, 'main', '', '../generator.php', '');
file_put_contents($this->settings['output_dir'] . '/index.html', $html);
}

private function getFolderIcon() {
return '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"/></svg>';
}

private function getFileIcon() {
return '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" class="icon"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><polyline points="14 2 14 8 20 8"/><path d="M10 13l-2 2 2 2"/><path d="M14 13l2 2-2 2"/></svg>';
}

}


/* ========= MERGE POINT: JSON INDEX ========= */

class phpDocGenerator {
    const VERSION = PHPDG_VERSION;

    // ════════════════════════════════════════════════════════════════════════════
    // PROPERTIES
    // ════════════════════════════════════════════════════════════════════════════

    private $settings = [];
    private $files = [];
    private $documentation = [];
    private $allClasses = [];
    private $allFunctions = [];
    private $fileTree = [];
    private $baseDir = null;
    private $lang = [];
    private $languages = [];
    private $translations = [];
    private $isCLI = false;
    private $fileIndex = [];  // File ID index for AJAX source viewer
    public $sseMode = false;  // Stream progress as SSE events

    // ════════════════════════════════════════════════════════════════════════════
    // TRAITS - Module methods
    // ════════════════════════════════════════════════════════════════════════════

    use ScannerModule;              // 08: scanDirectories(), scanDirectory(), findCommonBasePath()
    use ParserModule;               // 09: parseFiles(), parseFile(), parseDocBlock()
    use TreeBuilderModule;          // 10: buildFileTree(), fileExistsInTree()
    use OutputCreatorModule;        // 11: createOutputStructure(), generateHTMLFiles()
    use HtmlGeneratorModule;        // 12: generateFileHTML(), generateBreadcrumb()
    use ComponentsModule;           // 13: generateHeader(), generateLanguagePicker()
    use HtmlMethodsModule;          // 14: generateMethodHTML(), generateFunctionHTML()
    use DirectoryIndexesModule;     // 15: generateDirectoryIndexes(), generateMainIndex()
    use JsonIndexModule;            // 18: generateJsonIndex()

    // ════════════════════════════════════════════════════════════════════════════
    // CONSTRUCTOR
    // ════════════════════════════════════════════════════════════════════════════

    public function __construct($settings, $translations, $languages) {
        $this->settings = $settings;
        $this->translations = $translations;
        $this->languages = $languages;
        $this->lang = $translations[$settings['language']] ?? $translations['en'];
        $this->isCLI = php_sapi_name() === 'cli';
        $this->validateSettings();
    }

    /**
     * Output message with proper line break based on environment
     */
    private function output($message) {
        if ($this->sseMode) return;
        if ($this->isCLI) {
            echo $message . "\n";
        } else {
            echo htmlspecialchars($message) . "<br>\n";
        }
    }

    public function emitProgress($step, $current, $total, $label = '') {
        if (!$this->sseMode) return;
        $pct = $total > 0 ? (int)round($current * 100 / $total) : 0;
        $payload = json_encode([
            'step' => $step,
            'current' => $current,
            'total' => $total,
            'label' => $label,
            'pct' => $pct,
        ], JSON_UNESCAPED_UNICODE);
        echo "event: progress\ndata: {$payload}\n\n";
        @ob_flush();
        @flush();
    }

    private function shouldEmit($current, $total) {
        if (!$this->sseMode) return false;
        if ($current === 0 || $current === $total) return true;
        $interval = max(1, (int)($total / 100));
        return ($current % $interval) === 0;
    }

    private function validateSettings() {
        if (empty($this->settings['directories'])) {
            $this->output("❌ Missing 'directories' in settings!");
            exit(1);
        }
        if (empty($this->settings['output_dir'])) {
            $this->settings['output_dir'] = 'output';
        }
    }

    public function generate() {
        $this->output("🚀 Starting phpDocGenerator v" . self::VERSION . "...");
        $this->output("");

        $this->emitProgress('scan', 0, 1, 'Scanning directories');
        $this->scanDirectories();
        $this->emitProgress('scan', 1, 1, 'Scanning directories');

        $this->baseDir = $this->findCommonBasePath();
        $this->parseFiles();
        $this->buildFileTree();
        $this->createOutputStructure();
        $this->generateHTMLFiles();

        $this->emitProgress('dir-index', 0, 1, 'Generating directory indexes');
        $this->generateDirectoryIndexes();
        $this->emitProgress('dir-index', 1, 1, 'Generating directory indexes');

        $this->emitProgress('main-index', 0, 1, 'Generating main index.html');
        $this->generateMainIndex();
        $this->emitProgress('main-index', 1, 1, 'Generating main index.html');

        $this->emitProgress('htaccess', 0, 1, 'Creating .htaccess');
        $this->createHtaccess();
        $this->emitProgress('htaccess', 1, 1, 'Creating .htaccess');

        $this->emitProgress('json-index', 0, 1, 'Generating JSON file index');
        $this->generateJsonIndex();
        $this->emitProgress('json-index', 1, 1, 'Generating JSON file index');

        $this->output("");
        $this->output("✅ Done! Open {$this->settings['output_dir']}/index.html in your browser.");
    }

    private function createHtaccess() {
        $this->output("🔐 Creating .htaccess...");

        $htaccess = '';

        if (!empty($this->settings['http_auth'])) {
            $htpasswdContent = '';
            foreach ($this->settings['http_auth'] as $username => $password) {
                $htpasswdContent .= $username . ':' . crypt($password, base64_encode($password)) . "\n";
            }
            file_put_contents($this->settings['output_dir'] . '/.htpasswd', trim($htpasswdContent));

            $htpasswdPath = realpath($this->settings['output_dir'] . '/.htpasswd');

            $htaccess = <<<HTACCESS
# HTTP Authentication
AuthType Basic
AuthName "phpDocGenerator - {$this->lang['GENERATOR_PROTECTED_AREA']}"
AuthUserFile {$htpasswdPath}
Require valid-user

# Allow HTML and assets for authenticated users
<FilesMatch "\\.(html|css|js|png|jpg|gif|svg)$">
    Satisfy Any
</FilesMatch>


HTACCESS;
            $this->output("   ✓ {$this->lang['GENERATOR_AUTH_ENABLED']}");
            $this->output("   {$this->lang['GENERATOR_USERS']}:");
            foreach ($this->settings['http_auth'] as $username => $password) {
                $this->output("     - {$username}");
            }
        } else {
            $this->output("   ⚠   {$this->lang['GENERATOR_AUTH_DISABLED']}");
        }

        $htaccess .= <<<HTACCESS
# Block access to PHP files
<FilesMatch "\\.php$">
    Order Allow,Deny
    Deny from all
</FilesMatch>

# Allow access to HTML and assets
<FilesMatch "\\.(html|css|js|png|jpg|gif|svg)$">
    Order Allow,Deny
    Allow from all
</FilesMatch>

# Index files
DirectoryIndex index.html
HTACCESS;

        file_put_contents($this->settings['output_dir'] . '/.htaccess', $htaccess);
    }

    private function getHTMLTemplate($title, $content, $type, $rootPath = '', $generatorPath = 'generator.php', $currentRelativePath = '') {
        // Get translations as JSON for JavaScript
        $translationsJson = json_encode($this->translations, JSON_UNESCAPED_UNICODE);
        $languagesJson = json_encode($this->languages, JSON_UNESCAPED_UNICODE);
        $availableLanguagesJson = json_encode($this->settings['available_languages'], JSON_UNESCAPED_UNICODE);

        // Get direction from current language
        $direction = $this->languages[$this->settings['language']]['direction'] ?? 'ltr';

        $topBar = $this->generateTopBar($rootPath, $title, $currentRelativePath);
        $sidebar = $this->generateSidebarPanels($rootPath, $currentRelativePath);
        $statusBar = $this->generateStatusBar($title, $type);
        $searchIndexJson = $this->buildSearchIndexJson($rootPath);

        return <<<HTML
<!DOCTYPE html>
<html lang="{$this->settings['language']}" dir="{$direction}" data-theme="dark">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>PHPDG</title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Sofia+Sans:wght@400;500;600;700&display=swap" rel="stylesheet">
    <style>
    /* ============================================================================
   phpDG — design system v0.6
   ============================================================================
   Tokens
   - Background:     #0f1117 (base) / #16181f (card) / #090b10 (deep/status)
   - Border:         var(--border) / 0.12 hover
   - Accent:         #4f46e5 (indigo)  + #7c3aed (purple, gradient pair)
   - Text:           #f9fafb / #e5e7eb / #9ca3af / #6b7280 / #4b5563 / #374151
   - Visibility:     public #10b981 · protected #f59e0b · private #ef4444
   - Type:           teal #4ec9b0 · keyword #c586c0 · param #ce9178 · var #9cdcfe
   - Fonts:          Sofia Sans (UI) / system monospace (code)
   - Shell:          topbar 48 · sidebar 260 · statusbar 24
   ============================================================================ */


/* ── Color tokens (light / dark) ─────────────────────────────────────── */
:root {
  --bg:         #0f1117;
  --surface:    #16181f;
  --surface2:   #1a1d25;
  --topbar-bg:  #0f1117;
  --border:     var(--border);
  --border2:    var(--border2);
  --border3:    var(--border3);
  --hover:      var(--hover);
  --hover2:     var(--hover2);
  --subtle:     var(--subtle);
  --dot:        var(--hover2);
  --input-bg:   var(--border3);
  --input-bdr:  var(--input-bdr);
  --input-foc:  var(--border);
  --text:       #d4d4d4;
  --text-hi:    #f9fafb;
  --text-mid:   #d1d5db;
  --text-muted: #6b7280;
  --text-dim:   #4b5563;
  --text-sep:   #374151;
}
[data-theme="light"] {
  --bg:         #f9f7f4;
  --surface:    #f0ece6;
  --surface2:   #ffffff;
  --topbar-bg:  #1f2937;
  --border:     rgba(0,0,0,0.08);
  --border2:    rgba(0,0,0,0.06);
  --border3:    rgba(0,0,0,0.05);
  --hover:      rgba(0,0,0,0.04);
  --hover2:     rgba(0,0,0,0.02);
  --subtle:     rgba(0,0,0,0.025);
  --dot:        rgba(0,0,0,0.04);
  --input-bg:   rgba(0,0,0,0.04);
  --input-bdr:  rgba(0,0,0,0.12);
  --input-foc:  rgba(0,0,0,0.06);
  --text:       #1a1a1a;
  --text-hi:    #0d0d0d;
  --text-mid:   #2d2d2d;
  --text-muted: #6b6b6b;
  --text-dim:   #9b9b9b;
  --text-sep:   #c4bfb8;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
*::before, *::after { box-sizing: border-box; }
html, body { height: 100%; }
body {
    font-family: 'Sofia Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.55;
    overflow: hidden;
    font-size: 14px;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
}

/* ── Scrollbar ────────────────────────────────────────────────────── */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb { background: rgba(120,120,140,0.22); border-radius: 10px; }
::-webkit-scrollbar-thumb:hover { background: rgba(120,120,140,0.4); }
* { scrollbar-width: thin; scrollbar-color: rgba(120,120,140,0.22) transparent; }

/* ── Shell ────────────────────────────────────────────────────────── */
.app-shell {
    display: flex;
    flex-direction: column;
    height: 100vh;
    background: var(--bg);
}

.app-body {
    flex: 1;
    display: flex;
    overflow: hidden;
    min-height: 0;
}

/* ── Top bar ──────────────────────────────────────────────────────── */
.topbar {
    height: 48px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    background: var(--topbar-bg);
    border-bottom: 1px solid var(--border);
    z-index: 60;
}
.topbar-logo {
    width: 260px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    padding: 0 16px;
    border-right: 1px solid var(--border);
}
.topbar-logo a { display: flex; }
.topbar-logo svg { height: 22px; width: auto; display: block; color: white; }
.topbar-actions {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 0 16px;
    flex-shrink: 0;
    margin-left: auto;
}
.pill {
    font-size: 10px;
    padding: 3px 10px;
    border-radius: 20px;
    background: var(--hover);
    color: var(--text-muted);
    font-family: Consolas, Menlo, Monaco, monospace;
    white-space: nowrap;
}
.pill-version { color: var(--text-dim); }

/* ── Sidebar ──────────────────────────────────────────────────────── */
.sidebar {
    width: 260px;
    flex-shrink: 0;
    background: var(--surface);
    border-right: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    overflow: hidden;
}
.sidebar-tree {
    flex: 1;
    overflow-y: auto;
    padding: 6px 8px 12px;
}
.sidebar-search-results {
    flex: 1;
    overflow-y: auto;
    padding: 6px 10px 12px;
}

/* ── Sidebar tree items ───────────────────────────────────────────── */
.sb-tree-dir, .sb-tree-file {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 8px;
    border-radius: 6px;
    color: var(--text-mid);
    text-decoration: none;
    font-size: 13px;
    cursor: pointer;
    user-select: none;
    transition: background 0.1s;
}
.sb-tree-dir:hover, .sb-tree-file:hover { background: var(--hover); }
.sb-tree-file { padding-left: 28px; color: var(--text-mid); }
.sb-tree-file:hover { color: var(--text-mid); }
.sb-tree-file.is-active {
    background: rgba(79,70,229,0.16);
    color: #fff;
}
.sb-tree-dir-icon { color: #f59e0b; display: flex; flex-shrink: 0; }
[data-theme="light"] .sb-tree-dir-icon { color: #cc5500; }
.sb-tree-file-icon { color: #4f46e5; display: flex; flex-shrink: 0; }
.sb-tree-chevron {
    width: 12px;
    color: var(--text-muted);
    transition: transform 0.2s;
    display: flex;
    flex-shrink: 0;
}
.sb-tree-dir.expanded .sb-tree-chevron { transform: rotate(90deg); }
.sb-tree-children {
    margin-left: 12px;
    padding-left: 4px;
    border-left: 1px solid var(--border3);
    display: none;
}
.sb-tree-dir.expanded + .sb-tree-children { display: block; }

/* sidebar search */
.sidebar-search {
    padding: 10px 12px;
    border-bottom: 1px solid var(--border);
    flex-shrink: 0;
}
.sidebar-search-wrap {
    position: relative;
    display: flex;
    align-items: center;
}
.sidebar-search-icon {
    position: absolute;
    left: 9px;
    width: 14px;
    height: 14px;
    color: var(--text-muted);
    pointer-events: none;
    flex-shrink: 0;
}
.sidebar-search input {
    width: 100%;
    background: var(--input-bg);
    border: 1px solid var(--input-bdr);
    color: var(--text);
    border-radius: 8px;
    padding: 8px 10px 8px 30px;
    font-size: 13px;
    font-family: inherit;
    outline: none;
}
.sidebar-search input:focus { border-color: #4f46e5; background: var(--border); }
.sidebar-search input::placeholder { color: var(--text-dim); }

.sidebar-search-results { padding: 6px 10px; }
.sidebar-search-results .sb-result {
    padding: 6px 8px;
    border-radius: 6px;
    color: var(--text-mid);
    font-size: 12.5px;
    cursor: pointer;
    text-decoration: none;
    display: block;
}
.sidebar-search-results .sb-result:hover { background: var(--border3); }
.sidebar-empty {
    padding: 40px 14px;
    text-align: center;
    color: var(--text-dim);
    font-size: 12px;
}

/* ── Main content ─────────────────────────────────────────────────── */
.main {
    flex: 1;
    overflow-y: auto;
    background: var(--bg);
    position: relative;
}
.main::before {
    content: "";
    position: absolute;
    inset: 0;
    pointer-events: none;
    background-image: radial-gradient(circle, var(--dot) 1px, transparent 1px);
    background-size: 28px 28px;
    z-index: 0;
}
.container {
    position: relative;
    z-index: 1;
    max-width: 1100px;
    margin: 0 auto;
    padding: 22px 28px 32px;
}

/* ── Breadcrumb ───────────────────────────────────────────────────── */
.breadcrumb {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 6px;
    margin-bottom: 18px;
    font-size: 12px;
    color: var(--text-muted);
    font-family: Consolas, Menlo, Monaco, monospace;
}
.breadcrumb a { color: #4f46e5; text-decoration: none; }
.breadcrumb a:hover { color: #6366f1; text-decoration: underline; }
.breadcrumb .separator { color: var(--text-sep); }
.breadcrumb .current { color: var(--text-mid); }

/* ── File / class card ────────────────────────────────────────────── */
.file-header {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 14px;
    overflow: hidden;
    margin-bottom: 18px;
    box-shadow: 0 12px 36px rgba(0,0,0,0.25);
}
.file-header::before {
    content: "";
    display: block;
    height: 3px;
    background: linear-gradient(90deg, #4f46e5, #7c3aed);
}
.file-header-inner {
    padding: 18px 22px 18px;
}
.file-header h1 {
    font-size: 20px;
    font-weight: 700;
    color: var(--text-hi);
    letter-spacing: -0.02em;
    margin: 0;
    display: flex;
    align-items: center;
    gap: 10px;
}
.file-header .icon { color: #4f46e5; display: inline-flex; vertical-align: middle; }
.file-path {
    color: var(--text-muted);
    font-size: 12px;
    margin-top: 4px;
    font-family: Consolas, Menlo, Monaco, monospace;
}

/* ── Class card ───────────────────────────────────────────────────── */
.class {
    background: var(--surface);
    border: 1px solid var(--border);
    border-left: 3px solid #4f46e5;
    border-radius: 12px;
    padding: 16px 20px 18px;
    margin: 18px 0;
}
.class h2 {
    font-size: 16px;
    font-weight: 700;
    color: var(--text-hi);
    letter-spacing: -0.01em;
    margin-bottom: 10px;
    display: flex;
    align-items: center;
    gap: 8px;
}
.class .keyword {
    font-size: 10px;
    font-weight: 700;
    padding: 2px 8px;
    border-radius: 20px;
    background: rgba(197,134,192,0.15);
    color: #c586c0;
    letter-spacing: 0.05em;
    text-transform: lowercase;
}
.class-name { color: #4ec9b0; font-family: Consolas, Menlo, Monaco, monospace; font-weight: 600; }

h3 {
    color: #dcdcaa;
    font-size: 14px;
    font-weight: 600;
    margin: 16px 0 8px;
    letter-spacing: -0.01em;
}

/* ── Methods / functions ──────────────────────────────────────────── */
.methods-list { margin-top: 12px; display: flex; flex-direction: column; gap: 6px; }
.method-item, .function {
    background: var(--surface2);
    border: 1px solid var(--border2);
    border-radius: 10px;
    overflow: hidden;
    transition: border-color 0.15s;
}
.method-item:hover, .function:hover { border-color: var(--input-bdr); }
.method-item.is-open, .function.is-open { border-color: rgba(79,70,229,0.4); }

.method-header {
    padding: 10px 14px;
    cursor: pointer;
    user-select: none;
    display: flex;
    align-items: center;
    gap: 10px;
    font-family: 'Sofia Sans', sans-serif;
}
.method-header:hover { background: var(--hover2); }
.vis-dot {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    background: #6b7280;
    flex-shrink: 0;
}
.vis-public    { background: #10b981; box-shadow: 0 0 0 3px rgba(16,185,129,0.18); }
.vis-protected { background: #f59e0b; box-shadow: 0 0 0 3px rgba(245,158,11,0.18); }
.vis-private   { background: #ef4444; box-shadow: 0 0 0 3px rgba(239,68,68,0.18); }
.method-meta {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-left: auto;
    flex-shrink: 0;
}
.toggle-icon {
    color: var(--text-dim);
    width: 14px;
    height: 14px;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: transform 0.2s, color 0.15s;
    flex-shrink: 0;
}
.toggle-icon svg { display: block; }
.toggle-icon.expanded { transform: rotate(90deg); color: #4f46e5; }

.function-name {
    color: var(--text-mid);
    font-family: Consolas, Menlo, Monaco, monospace;
    font-weight: 600;
    font-size: 13px;
}
.params-preview {
    color: var(--text-dim);
    font-family: Consolas, Menlo, Monaco, monospace;
    font-size: 11.5px;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    max-width: 380px;
    flex: 1;
    min-width: 0;
}
.method-header .keyword {
    font-size: 9.5px;
    font-weight: 700;
    padding: 2px 7px;
    border-radius: 20px;
    background: rgba(197,134,192,0.13);
    color: #c586c0;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}
.badge-vis {
    font-size: 9.5px;
    font-weight: 700;
    padding: 2px 0;
    border-radius: 20px;
    letter-spacing: 0.04em;
    flex-shrink: 0;
    min-width: 72px;
    text-align: center;
}
.badge-vis.public    { background: rgba(16,185,129,0.15);  color: #10b981; }
.badge-vis.protected { background: rgba(245,158,11,0.15);  color: #f59e0b; }
.badge-vis.private   { background: rgba(239,68,68,0.15);   color: #ef4444; }
[data-theme="light"] .badge-vis.public    { color: #0a6640; }
[data-theme="light"] .badge-vis.protected { color: #cc5500; }
[data-theme="light"] .badge-vis.private   { color: #b91c1c; }

.method-details {
    padding: 0 14px 14px 30px;
    border-top: 1px solid var(--border2);
}
.description {
    color: var(--text);
    margin: 12px 0;
    padding: 10px 12px;
    background: var(--subtle);
    border-left: 2px solid #4f46e5;
    border-radius: 6px;
    font-size: 13px;
    line-height: 1.6;
}
.parameters { margin: 12px 0; }
.parameters > strong {
    display: block;
    font-size: 11px;
    font-weight: 700;
    color: var(--text-muted);
    text-transform: uppercase;
    letter-spacing: 0.06em;
    margin-bottom: 6px;
}
.param {
    background: var(--subtle);
    padding: 7px 11px;
    margin: 4px 0;
    border-left: 2px solid #ce9178;
    border-radius: 4px;
    font-family: Consolas, Menlo, Monaco, monospace;
    font-size: 12px;
}
.type { color: #4ec9b0; }
.var { color: #9cdcfe; }
.param-desc { color: var(--text-muted); font-family: 'Sofia Sans', sans-serif; }
.return {
    margin: 12px 0 6px;
    padding: 8px 12px;
    background: var(--subtle);
    border-left: 2px solid #c586c0;
    border-radius: 4px;
    font-size: 12px;
    color: var(--text);
    font-family: Consolas, Menlo, Monaco, monospace;
}
.return .keyword {
    color: #c586c0;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-size: 10px;
    margin-right: 6px;
}

/* ── View source button ───────────────────────────────────────────── */
.source-view-button {
    margin-top: 12px;
    padding-top: 12px;
    border-top: 1px solid var(--border2);
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}
.btn-view-source {
    background: rgba(79,70,229,0.15);
    color: #a5b4fc;
    border: 1px solid rgba(79,70,229,0.3);
    padding: 6px 12px;
    border-radius: 7px;
    cursor: pointer;
    font-size: 12px;
    font-weight: 500;
    font-family: 'Sofia Sans', sans-serif;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: background 0.15s, border-color 0.15s;
}
.btn-view-source:hover { background: rgba(79,70,229,0.25); border-color: rgba(79,70,229,0.5); }
[data-theme="light"] .btn-view-source { color: #4338ca; border-color: rgba(79,70,229,0.45); }
[data-theme="light"] .btn-view-source:hover { background: rgba(79,70,229,0.2); border-color: rgba(79,70,229,0.65); }
.btn-view-source::before {
    content: "</>";
    font-family: Consolas, Menlo, Monaco, monospace;
    font-size: 11px;
    opacity: 0.7;
}
.btn-copy-source {
    background: var(--border3);
    color: #9ca3af;
    border: 1px solid rgba(255,255,255,0.1);
    padding: 6px 12px;
    border-radius: 7px;
    cursor: pointer;
    font-size: 12px;
    font-weight: 500;
    font-family: 'Sofia Sans', sans-serif;
    display: inline-flex;
    align-items: center;
    gap: 6px;
    transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.btn-copy-source:hover { background: rgba(255,255,255,0.09); border-color: rgba(255,255,255,0.18); color: var(--text-mid); }
[data-theme="light"] .btn-copy-source { color: #374151; border-color: rgba(0,0,0,0.15); }
[data-theme="light"] .btn-copy-source:hover { background: rgba(0,0,0,0.06); border-color: rgba(0,0,0,0.25); color: #1f2937; }
.btn-copy-source.copied { background: rgba(16,185,129,0.12); border-color: rgba(16,185,129,0.35); color: #34d399; }

/* ── Stats (home page) ────────────────────────────────────────────── */
.stats-row {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 12px;
    margin: 0 0 22px;
}
.stat-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 18px 20px;
    position: relative;
    overflow: hidden;
}
.stat-card::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: linear-gradient(90deg, #4f46e5, #7c3aed);
    opacity: 0.7;
}
.stat-number {
    font-size: 32px;
    font-weight: 700;
    color: var(--text-hi);
    letter-spacing: -0.03em;
    line-height: 1;
    display: block;
    font-family: 'Sofia Sans', sans-serif;
}
.stat-label {
    color: var(--text-muted);
    font-size: 11px;
    text-transform: uppercase;
    letter-spacing: 0.07em;
    margin-top: 8px;
    display: block;
    font-weight: 600;
}

/* ── Homepage symbol index ────────────────────────────────────────── */
.index-section {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 20px 24px;
    margin-bottom: 14px;
}
.index-section-title {
    color: var(--text-hi);
    font-size: 13px;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    margin: 0;
    padding: 0;
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    user-select: none;
}
.index-section-title:hover { color: #a5b4fc; }
.index-section.open .index-section-title {
    margin-bottom: 12px;
    padding-bottom: 10px;
    border-bottom: 1px solid var(--border2);
}
.index-chevron {
    display: flex;
    align-items: center;
    color: var(--text-muted);
    transition: transform 0.15s;
}
.index-section.open .index-chevron { transform: rotate(90deg); }
.index-count {
    margin-left: auto;
    font-size: 11px;
    font-weight: 500;
    letter-spacing: 0;
    text-transform: none;
    color: var(--text-muted);
    background: var(--border2);
    border-radius: 10px;
    padding: 1px 8px;
}
.index-table { display: flex; flex-direction: column; gap: 2px; }
.index-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 7px 10px;
    border-radius: 7px;
    text-decoration: none;
    transition: background 0.1s;
    gap: 12px;
}
.index-row:hover { background: #1f2230; }
.index-symbol {
    font-size: 13px;
    font-weight: 600;
    color: #a5b4fc;
    font-family: 'JetBrains Mono', 'Fira Code', monospace;
    white-space: nowrap;
}
.index-file {
    font-size: 11px;
    color: var(--text-muted);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    text-align: right;
}
.index-file-dir { color: var(--text-dim); }

/* ── Directory index / project tree ───────────────────────────────── */
.directory-index, .main-tree {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 22px 24px;
    margin-top: 12px;
}
.directory-index h1, .main-tree h2 {
    color: var(--text-hi);
    font-size: 16px;
    font-weight: 700;
    letter-spacing: -0.01em;
    margin-bottom: 14px;
    display: flex;
    align-items: center;
    gap: 8px;
}
.directory-index .icon, .main-tree .icon { color: #f59e0b; }
[data-theme="light"] .directory-index .icon, [data-theme="light"] .main-tree .icon { color: #cc5500; }

.tree { margin-left: 4px; }
.tree-item {
    padding: 7px 12px;
    margin: 4px 0;
    background: var(--surface2);
    border: 1px solid var(--border3);
    border-radius: 8px;
    transition: background 0.1s, border-color 0.1s;
    display: flex;
    align-items: center;
    gap: 8px;
}
.tree-item:hover { background: #1f2230; border-color: rgba(255,255,255,0.1); }
.tree-item a {
    color: var(--text-mid);
    text-decoration: none;
    font-size: 13px;
    flex: 1;
}
.tree-item a:hover { color: #fff; }
.tree-item .icon { color: #4f46e5; flex-shrink: 0; }
.tree-dir > .icon, .tree-dir-icon { color: #f59e0b; }
[data-theme="light"] .tree-dir > .icon, [data-theme="light"] .tree-dir-icon { color: #cc5500; }
.tree-dir .tree-children { margin-left: 18px; margin-top: 4px; }
.folder-toggle {
    color: var(--text-muted);
    cursor: pointer;
    user-select: none;
    display: inline-block;
    width: 12px;
    transition: transform 0.2s;
    font-size: 10px;
    flex-shrink: 0;
}
.folder-toggle.expanded { transform: rotate(90deg); color: #4f46e5; }

/* ── Status bar ───────────────────────────────────────────────────── */
.statusbar {
    height: 24px;
    flex-shrink: 0;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 16px;
    background: #090b10;
    border-top: 1px solid var(--border3);
    font-size: 10px;
    color: var(--text-sep);
    font-family: Consolas, Menlo, Monaco, monospace;
}
.statusbar-left, .statusbar-right { display: flex; align-items: center; gap: 12px; }
.statusbar .pill { padding: 1px 7px; font-size: 9.5px; }
.status-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #10b981;
    box-shadow: 0 0 6px rgba(16,185,129,0.5);
}

/* ── Language picker ──────────────────────────────────────────────── */
.language-picker { position: relative; }
.lang-current {
    display: flex;
    align-items: center;
    gap: 6px;
    padding: 4px 8px 4px 4px;
    background: var(--hover);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 7px;
    cursor: pointer;
    transition: background 0.15s, border-color 0.15s;
}
.lang-current:hover { background: var(--border); border-color: rgba(255,255,255,0.16); }
[data-theme="light"] .lang-current .lang-name  { color: #d1d5db; }
[data-theme="light"] .lang-current .lang-arrow { color: #9ca3af; }
.lang-current svg { width: 22px; height: 14px; border-radius: 2px; }
.lang-name {
    color: var(--text-mid);
    font-size: 11px;
    white-space: nowrap;
    font-weight: 500;
}
.lang-arrow {
    color: var(--text-muted);
    font-size: 8px;
    margin-left: 2px;
    transition: transform 0.2s;
}
.lang-current.active .lang-arrow { transform: rotate(180deg); }
.lang-dropdown {
    position: absolute;
    top: calc(100% + 6px);
    right: 0;
    background: var(--surface);
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 8px;
    box-shadow: 0 12px 32px rgba(0,0,0,0.4);
    z-index: 1000;
    min-width: 160px;
    padding: 4px;
}
.lang-option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 7px 9px;
    cursor: pointer;
    transition: background 0.15s;
    border-radius: 5px;
}
.lang-option:hover { background: var(--border2); }
.lang-option svg { width: 22px; height: 14px; border-radius: 2px; }

/* ── Modal (source viewer) ────────────────────────────────────────── */
.modal {
    display: none;
    position: fixed;
    z-index: 10000;
    inset: 0;
    background: rgba(0,0,0,0.72);
    backdrop-filter: blur(4px);
    -webkit-backdrop-filter: blur(4px);
    animation: fadeIn 0.18s;
}
@keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } }
.modal-content {
    background: var(--surface);
    margin: 50px auto;
    padding: 0;
    border: 1px solid rgba(79,70,229,0.4);
    width: 92%;
    max-width: 1200px;
    max-height: 80vh;
    border-radius: 14px;
    box-shadow: 0 24px 64px rgba(0,0,0,0.5), 0 0 0 1px rgba(79,70,229,0.2);
    animation: slideDown 0.25s;
    overflow: hidden;
    display: flex;
    flex-direction: column;
}
@keyframes slideDown {
    from { transform: translateY(-30px); opacity: 0; }
    to { transform: translateY(0); opacity: 1; }
}
.modal-header {
    background: var(--bg);
    padding: 14px 20px;
    border-bottom: 1px solid var(--border);
    display: flex;
    flex-direction: column;
    gap: 4px;
    flex-shrink: 0;
    position: relative;
}
.modal-title-row {
    display: flex;
    align-items: center;
    gap: 10px;
    padding-right: 32px;
}
.modal-header h3 {
    margin: 0;
    color: var(--text-hi);
    font-size: 14px;
    font-weight: 700;
    letter-spacing: -0.01em;
    font-family: Consolas, Menlo, Monaco, monospace;
}
.modal-copy-btn {
    background: none;
    border: none;
    padding: 4px;
    cursor: pointer;
    color: var(--text-muted);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 5px;
    transition: background 0.15s, color 0.15s;
    flex-shrink: 0;
}
.modal-copy-btn:hover { background: var(--border2); color: var(--text-mid); }
.modal-copy-btn.copied { color: #34d399; }
.modal-header .file-info {
    color: var(--text-muted);
    font-size: 11px;
    font-family: Consolas, Menlo, Monaco, monospace;
}
.modal-close {
    color: var(--text-muted);
    font-size: 22px;
    cursor: pointer;
    background: none;
    border: none;
    padding: 0;
    width: 28px;
    height: 28px;
    line-height: 1;
    border-radius: 7px;
    transition: background 0.15s, color 0.15s;
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    top: 12px;
    right: 16px;
}
.modal-close:hover { color: var(--text-mid); background: var(--border2); }
.modal-body {
    padding: 18px;
    overflow-y: auto;
    flex: 1;
}
.modal-body pre {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    padding: 16px;
    border: 1px solid var(--border);
    border-radius: 10px;
    overflow-x: auto;
    font-family: Consolas, Menlo, Monaco, monospace;
    font-size: 12.5px;
    line-height: 1.65;
}
.modal-body pre code { color: var(--text); }
.loading { text-align: center; padding: 40px; color: var(--text-muted); font-size: 13px; }
.error { text-align: center; padding: 40px; color: #ef4444; font-size: 13px; }

/* ── RTL support ──────────────────────────────────────────────────── */
[dir="rtl"] .breadcrumb .separator { display: inline-block; transform: scaleX(-1); }
[dir="rtl"] .class { border-left: 1px solid var(--border); border-right: 3px solid #4f46e5; }
[dir="rtl"] .description, [dir="rtl"] .param, [dir="rtl"] .return {
    border-left: none;
    border-right-style: solid;
    border-right-width: 2px;
}
[dir="rtl"] .description { border-right-color: #4f46e5; }
[dir="rtl"] .param { border-right-color: #ce9178; }
[dir="rtl"] .return { border-right-color: #c586c0; }
[dir="rtl"] .topbar-logo { border-right: none; border-left: 1px solid var(--border); }
[dir="rtl"] .sidebar { border-right: none; border-left: 1px solid var(--border); }
[dir="rtl"] .sb-tree-children { margin-left: 0; margin-right: 12px; padding-left: 0; padding-right: 4px; border-left: none; border-right: 1px solid var(--border3); }
[dir="rtl"] .tree-dir .tree-children { margin-left: 0; margin-right: 18px; }
[dir="rtl"] .toggle-icon { margin-left: 0; margin-right: auto; }
[dir="rtl"] .lang-dropdown { right: auto; left: 0; }
[dir="rtl"] .lang-current, [dir="rtl"] .lang-option { flex-direction: row-reverse; }

/* ── Responsive ───────────────────────────────────────────────────── */
@media (max-width: 880px) {
    .sidebar { width: 220px; }
    .topbar-logo { width: 220px; }
    .container { padding: 18px 16px 24px; }
    .stats-row { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
    .sidebar { display: none; }
    .topbar-logo { width: auto; border-right: none; }
    .topbar-actions .pill-version { display: none; }
}


/* ── Theme switch (pill) ──────────────────────────────────────────── */
.theme-switch {
    position: relative;
    width: 58px;
    height: 28px;
    border-radius: 7px;
    background: var(--hover);
    border: 1px solid rgba(255,255,255,0.1);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 0 6px;
    flex-shrink: 0;
    transition: background 0.25s;
    user-select: none;
}
.theme-switch:hover { background: rgba(255,255,255,0.08); border-color: rgba(255,255,255,0.16); }
.ts-knob {
    position: absolute;
    top: 3px;
    width: 22px;
    height: 22px;
    border-radius: 5px;
    background: rgba(255,255,255,0.15);
    transition: transform 0.25s cubic-bezier(.4,0,.2,1), background 0.25s;
    transform: translateX(29px);
    box-shadow: 0 2px 6px rgba(0,0,0,0.35);
    z-index: 1;
    left: 3px;
}
[data-theme="light"] .ts-knob {
    transform: translateX(0px);
}
.ts-icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 14px;
    height: 14px;
    z-index: 2;
    position: relative;
    transition: color 0.2s;
}
.ts-sun  { color: #6b7280; }
.ts-moon { color: #f9fafb; }
[data-theme="light"] .ts-sun  { color: #f9fafb; }
[data-theme="light"] .ts-moon { color: #9b9b9b; }
    </style>
<link rel="icon" type="image/svg+xml" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbDpzcGFjZT0icHJlc2VydmUiIHdpZHRoPSIyMTMzcHgiIGhlaWdodD0iMjEzM3B4IiB2ZXJzaW9uPSIxLjEiIHN0eWxlPSJzaGFwZS1yZW5kZXJpbmc6Z2VvbWV0cmljUHJlY2lzaW9uOyB0ZXh0LXJlbmRlcmluZzpnZW9tZXRyaWNQcmVjaXNpb247IGltYWdlLXJlbmRlcmluZzpvcHRpbWl6ZVF1YWxpdHk7IGZpbGwtcnVsZTpldmVub2RkOyBjbGlwLXJ1bGU6ZXZlbm9kZCINCnZpZXdCb3g9IjAgMCAyMTMzIDIxMzMiDQogeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPg0KIDxnIGlkPSJMYXllcl94MDAyMF8xIj4NCiAgPGcgaWQ9Il8yNDQ5NDM3OTM2MTQ0Ij4NCiAgIDxpbWFnZSBpZD0iT2JqZWN0X3gwMDIwXzkiIHg9IjAiIHk9IjI2NyIgd2lkdGg9IjIxMzMiIGhlaWdodD0iMTYwMCIgeGxpbms6aHJlZj0iZGF0YTppbWFnZS9wbmc7YmFzZTY0LGlWQk9SdzBLR2dvQUFBQU5TVWhFVWdBQUFnQUFBQUdBQ0FZQUFBR3NKK29wQUFBQUNYQklXWE1BDQpBQXNTQUFBTEVnSFMzWDc4QUFBSk5rbEVRVlI0bk8zZHNXM2xRQlFFUVJrYkJoZGcva2xTV2Z3eHVpcUNCZkhVbWpPRU8vZDV2Nyt3DQpzMzdBbWcrd2ZzQ2FEN0Ird0pvUHNIN0FtZyt3ZnNDYUQ3Qit3Sm9Qc0g3QW1nK3dmc0NhRDdCK3dKb1BzSDdBbWcrd2ZzQ2FEN0IrDQp3Sm9Qc0g3QW1nK3dmc0NhRDdCK3dKb1BzSDdBbWcrd2ZzQ2FEN0Ird0pvUHNIN0FtZyt3ZnNDYUQ3Qit3Sm9Qc0g3QW1nK3dmc0NhDQpEN0Ird05yeDl3SnhQc0Q2QVdzK3dQb0JhejdBK2dGclBzRDZBV3Mrd1BvQmF6N0ErZ0ZyUHNENkFXcyt3UG9CYXo3QStnRnJQc0Q2DQpBV3Mrd1BvQmF6N0ErZ0ZyUHNENkFXcyt3UG9CYXo3QStnRnJQc0Q2QVdzK3dQb0JhejdBK2dGclBzRDZBV3Mrd1BvQmF6N0ErZ0ZyDQpQc0Q2QVdzK3dQb0JhL20vRjZqTC93VFVPWUE0QnhEbkFPSWNRSndEaUhNQWNRNGd6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnDQp6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnemdIRU9ZQTRCeERuQU9JY1FKd0RpSE1BY1E0Z3pnSEVPWUE0QnhEbkFPSWNRSndEDQppSE1BY1E0Z3pnSEVPWUE0QnhEbkFPSWNRSndEaUhNQWNmNi9nRGdGaUhNQWNRNGd6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnDQp6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnemdIRU9ZQTRCeERuQU9JY1FKd0RpSE1BY1E0Z3pnSEVPWUE0QnhEbkFPSWNRSndEDQppSE1BY1E0Z3pnSEVPWUE0QnhEbkFPSWNRSndEaUhNQWNRNGd6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnemdIRU9ZQTRCeERuDQpBT0ljUUp3RGlITUFjUTRnemdIRU9ZQTRCeERuQU9JY1FKd0RpSE1BY1E0Z3pnSEVPWUE0QnhEbkFPSWNRSndEaUhNQWNRNGd6Z0hFDQpPWUE0QnhEbkFPSWNRSndEaUhNQWNRNGd6Z0hFT1lBNEJ4RG5BT0ljUUp3RGlITUFjUTRnemdIRU9ZQTRCeERuQU9MT2ZkNXYvUWhnDQp3MjhBQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BDQpDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BDQpDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BDQpDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BDQpDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BQ0JNQUNCTUFDQk1BDQpDRHYzZWIvMUk0QU5Dd0RDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDQkFEQ0JBRENCQURDDQpCQURDQkFEQ0JBRENCQURDem4zZWIvMElBT0MzL0FzQUFJSU1BQUFJTWdBQUlNZ0FBSUFnQXdBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEDQpBQUNDREFBQUNESUFBQ0RJQUFDQUlBTUFBSUlNQUFBSU1nQUFJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBDQpDRElBQUNESUFBQ0FJQU1BQUlJTUFBQUlNZ0FBSU1nQUFJQWdBd0FBZ2d3QUFBZ3lBQUFneUFBQWdDQURBQUNDREFBQUNESUFBQ0RJDQpBQUNBSUFNQUFJSU1BQUFJTWdBQUlNZ0FBSUFnQXdBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEQUFDQ0RBQUFDRElBQUNESUFBQ0FJQU1BDQpBSUlNQUFBSU1nQUFJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBQ0RJQUFDRElBQUNBSUFNQUFJSU1BQUFJDQpNZ0FBSU1nQUFJQWdBd0FBZ2d3QUFBZ3lBQUFneUFBQWdDQURBQUNDREFBQUNESUFBQ0RJQUFDQUlBTUFBSUlNQUFBSU1nQUFJTWdBDQpBSUFnQXdBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEQUFDQ0RBQUFDRElBQUNESUFBQ0FJQU1BQUlJTUFBQUlNZ0FBSU1nQUFJQWdBd0FBDQpnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBQ0RJQUFDRElBQUNBSUFNQUFJSU1BQUFJTWdBQUlNZ0FBSUFnQXdBQWdnd0FBQWd5DQpBQUFneUFBQWdDQURBQUNDREFBQUNESUFBQ0RJQUFDQUlBTUFBSUlNQUFBSU1nQUFJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBDQpnQ0FEQUFDQ0RBQUFDRElBQUNESUFBQ0FJQU1BQUlJTUFBQUlNZ0FBSU1nQUFJQWdBd0FBZ2d3QUFBZ3lBQUFneUFBQWdDQURBQUNDDQpEQUFBQ0RJQUFDRElBQUNBSUFNQUFJSU1BQUFJTWdBQUlNZ0FBSUFnQXdBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEQUFDQ0RBQUFDRElBDQpBQ0RJQUFDQUlBTUFBSUlNQUFBSU1nQUFJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBQ0RJQUFDRElBQUNBDQpJQU1BQUlJTUFBQUlNZ0FBSU1nQUFJQWdBd0FBZ2d3QUFBZ3lBQUFneUFBQWdDQURBQUNDREFBQUNESUFBQ0RJQUFDQUlBTUFBSUlNDQpBQUFJTWdBQUlNZ0FBSUFnQXdBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEQUFDQ0RBQUFDRElBQUNESUFBQ0FJQU1BQUlJTUFBQUlNZ0FBDQpJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBQ0RJQUFDRG9IMFpyRktucnVqUkZBQUFBQUVsRlRrU3VRbUNDDQoiLz4NCiAgIDxpbWFnZSBpZD0iREciIHg9IjIxMiIgeT0iNTcxIiB3aWR0aD0iMTcwNCIgaGVpZ2h0PSI5OTYiIHhsaW5rOmhyZWY9ImRhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBWmtBQUFEdkNBWUFBQUZYcnBrd0FBQUFDWEJJV1hNQQ0KQUFzU0FBQUxFZ0hTM1g3OEFBQWY5MGxFUVZSNG5PMmRqYlhiTmcrRzBYTTZRTE9CTTBIVENhcE8wSFNDT0JNa25TRHVCRWtuaUR0Qg0KMHdtcVR0QjJnbnFEZG9KOG45OHI4MXJYbG14UklnaUNlcDl6bFB1VGE1b3lCUUlFUVBETHo1OC9TOEc4UFY2SDQvVnA2Z3UrUEY3Lw0KbS9sbXI0L1hmdVpyaDRqdHh4ZER2L3h5UVFjK25pN3c3SGo5TjdPZHVSOW9lTjJURzF0eVEzMytIV3A4QW5OdjVyS054L2ROZFVPRA0KalUvNDIrVHZlK3VHZnJ2NCtmdll4aGN3OXZxN0g4S3RHM3A1NTdWL0hhK3ZiN3p4clpzYTY5aTlEeUw4LzlEckg5NXp5U1AzNGtiag0KYzNpZW9wRVVNb1JQYmVpbW11UFZEdnoreGNEdndDSEJleWFmRlByOExzT1AwSitLNzVuc2hrWS9zZHhvamxBTWx6UHFGSkpiQ2tYQw0KR3lvZER6Y1VNOWtzVXF4Rndoc3FIUTgzRkdWNXA3cWhwVmJDMUtYSlhUUkg2QS9GdGtkSmNVTmpvOU9NL0Y3VjdsdDZReXJMNkNYdg0KTy9lR0d1bVdCMlBNWFlKUHVhbWJIK0t0RzlKY0R0eDY3TUx2djVGdW1RL2djSHcvcFdHTlNXR3BneVF3YXlHWThvYjZuK2dVbGs0Tw0KZzY5UGNVTi95N2lmNEI3bzFPVEg2ZUoxZytDR2ZveHNFS3ZMZXk2dUdENmNycTJjWGN0ajNIdWNYM3haY1BRQm85NUk1em1hOUNndg0KaVR5a0V2eEExSnBuNkpkTFpLZi81a3R1Yk02SHFScHhRT056NUdtcGZzUHI0V1U5NEllVTAvVDNZaE50K0VmdVJCb3VmV0liR1hmQw0KWDRJcDk4T2R2N2wxSTdESW00SGYzdzBFak4zTWxNZGxyRU9ZNnUvZHpCaTNSdlZ1RUdESlkzYlA1b3FONDB4OVBNZmU5MzlMWlNiVg0KMnVXN0JHMm9oa3BpYUJQMHc0WHpZNGdoTTB6VmVaZ2lmanBHc09tZTRIVmtCdUhObEVycE54TTFTNVorTTFId1prcEY4MmFlSldnag0KS2lWRzgyYm01cnZOUnRPeHJzbWdpNnNVbVlrMWZRYTluMW9SQWkyYjdDWnpieWE1aTFXbWowNzBTbk5wWitjUzN2ZlNEekNwUDZsbA0KWnVuU04vRHRuZjhmSk9YTnhJN0lraFhxRDhmcjE4dGZwbG8yTDNudDNJVHduNC9YbS81L3pMbVoySmpNUFc0bHFmYTU5SmpDUC9mMA0KWms1UmdMbHhsakZTM3F3bEtReUMyVS91a3FoR0treDA3QUJhbjhOUXU1UHV1UVFMN2JMek9RZkw2c0djRk9FcVlYQXVTUldhbS9vZQ0KMWd5R0EwR0pnOU5udE9NTDJ5dVJxM3VOSFp5NUh4SU1qaVY3SmxMNDVPY01ESUlQYzRPQ0FKc3BZNU1qSjIwT1M4bGZjdjNoeG41WQ0KU3dZb3llYk5HUVJUZVNOZG5Id3ErUHVENWJRMmRUM1FSek9xRmRCby95QnhDN3FIaEljU2RBNDZIU1Arc1FPME9QSElpaElHQjBEOA0KUzFiV0pwUXlPQ0JHN0hlbkt5Vnp0Z3ZHRWlXWkpRMU9ETzhrL2VBVWg5ZkJXUVVjbklMaDRDeERkVk1QQjZkZ09EZ0Z3OEVwR0srRA0KODR0MUIwN004U2hNMWxNbERjN2tjbmpTN2RSTHpVYWh6VVdVTkRqSjZnN01aT3BHcVd5VU1qaWF6a2xNZ2E4aVg2T0ZxNXoxMkhYQw0KSEYyemxlbURveG1TMk1hK3dHSnd2cEp6YmMwWXNGVitPL005WTNhMVk0REc5bWpPWmRaaVZYTndFSnJlUzVxNS9ISHI4RXdRYW80cA0KT2REUE5aMGJxbDdzUFlnZEhJdVlTNnBwWm02aGlmY3pYcE1FYTUxekM0MjVQMnl3dEF6c1RZNWJsVFk0dWNMRWMvSVhsb0pNOVppMQ0Kbk9uZ2xCQ3Y3L2RCYTZDRzdoUGI0dTRaUlMrL0hIbnhHaG43SERBTnZobjV2ejR4dXhYK3UvRitqNVJjYTZoVVFnMmtRQ3NLdXlvZw0KTlZoemJCSzJXY3ZXajZuU2NvdlpwMXBnWU9Zc0JPZXlwTlphRGxJTVJwLys2UnpZNGZWMjZndHpHd0ZZaFBhVmJiVFZvc1N0aWt5cA0KZUNQblFiK3ZZM1Q3Y3BmK3BrY3JROFJpallQM3ZHa3dXQTlNbjdsVjVPYlNTdWVTc1NMc3NIQnhaa0ZzUmJ5NWxKVGlPM2kvcFExTQ0KUUhOd1NocVV3Tlg5bGpvd1FHTndkb25iUzhtVCt5MTVZRURxd1htWHNDMVZZZ1ptU25hOVJudy8xZUFzbWNKaTRrUWJpZHVkMW1mVw0KVnNJbDF0TFNkVUlPZzJDSU9lOTVrQVNlN0Z4VFdYKzFiN1Z1aUNGVjJIbE9MWmliSllZMVFXZDNFai9mNTVTYUptRmJzeW9QV1NuLw0KM2VuS0lUMU41TjlyREg3MDRGaGJaVk1DUjMyZ3EyS2RvTGNPZkxta21QaVU5Y0RFMW9Zc0xxc3lBdWl0eVM0ZzY0RUJ4UndTcXN4Vw0KSXN6b0VnWUdJRTR6VlJxMmt2Wkk5WUQyTkhhSStlTlNCZ1o2WTZyVUlQQzAxK3RLR1pReU1GcVVIQzI5U2UwRFV4cVRwOHVTQmdhbg0KcGNTWXRsVlQwc0MwMWgwb2laSUdodlRnd0JRS0I2WlFPRENGd29FcEZBN01mQkRSdlRxbElSRXNFTFNBaldiakhKaEM0Y0FVQ2dlbQ0KVURnd2hjS0JLWlNTQnNaYjdDUzJDa2NVSlEzTTNyb0RNNGdOUjdzc091YzVBeVk1SlEwTTZlRnhZR0pxK3J2ZDJsN0t3TVRrbGVYYQ0KbzJsS0tRTlRBdGlEditSb3JhU1VNRENsWkdIQzlPWEFuSWlkbHI1UjZVVWVkakYvYkQwd3NmRU1iV1UrWnpmQlZLTDJBMWtOekVibQ0KNzFPTUpTWnBYV3N0NVdMajBseWRrbXZ2U3VxZGE3T3N5SndEczBUSjU2NzliNzVUV25OZzVsUnhIV083OFBWek42bUcxOGF5T0I4Zw0KWm1Dc3pGcnI3WGY5K3g2cnpmemk5UHRrUllPc3JiSjdwQnlVRkR2WGN0VmxmbEh5d0R4WGFMT0ViWVZUOW1KK1ZlckFhRTVmcUNxbw0KbFE4MmhVYnVQeHhGU295MlRrR3BSOVNuVEZuN2NpcFQ3KzE5U1FPVFU4bkRZdHhKM2tLdDdvNEh0cks2UW1IcUhEb24raDZ0QnFhVQ0KNnJGQXMrYi83SWN1eDhETVBaY2xOeWtINk42QTNOVnhyTzkvVGYvendNTHh6N0UvN0JGVjdQcjB0emYvbnJYOVNRcmdndHFLM2dtTw0KV1B0OU9sMEhwZmVZREdhejFDWHRMY0NIMmtyM29icE5qaWtZbk0zUmlsMzYzN2VuNjVaSERFRUlhSWpZb2w3UlFHaThDd3dJSCtxVQ0KSUc1SkJudXA1RGlLSWpXdjVQcFVWSlV6V0Vwd0FlUm15Sk9aK3RSU2IrekVVZFh3Q0M3UHgwbHl1c2NhaFdhSS9tbXlnZG9YNFZzNQ0Kbnd5MUZzTEpLMkQyUkVtaEdhY3ZSRXVQaEM0SjY0QnVLZlFuU2xTZG5yd1dvdEJNbzU5SDZsVURVVmpHQ1NIVVNaTWpoU2FlSmRtQg0KRmxCWXBoTW14NXRqUzZHWmp3ZmhvY0RNQTUvYjZESE5GSnJsbENnOE83SDNoaUZ1c3BkNUZaMGI2UndWbHk3a25NQko4bElHdkcxYQ0KUXFQOUFDSFl0cFh1aGl3UDdlMWpkZnpkSlloQmFVWG1oeGlka1JmUW5xN3R3UCtsM1B4ekQzeU8rRHlmQ0k1WFRRTlB4d2NaVDJpYg0KbXBlVUdnaU9aZkEwbDhCWVRnNzljZCtJL21aZmZKNFFtc2N4OVNvMDkwQkUrM0pnYzluM0NKN0dKZ21tQUFPcktUQWxCb0FQb3BzRw0KSGZpMTl6N1ZDczBRNGFZM29qODdJVFhwSUhsVHV6WDNiSlZnZHQ0RGZXeEZ6MXpIV0Q1TWhHc1Ntc0JCOHN4T3NMdjNraUdCVUhTVA0KVkQwSVRLQVJQUk1WRStGcWhhWVBIZ2pOaGVXL2t1ZWgwMHF1OUNRd0FaaXBxcWI0Mm9VR2hJV2wxZ2V0V1pvTGFKbUFIZ1VtZ0YyUA0KcTZpaGJZM1dwbWZ0Rkh1TnJSMC9LclNaazlVVW5pOEJMY0hSMWphcDhiQTMzUXdLelRVYUJXcThiZWdpMS93UnZxSFFYQVBIZ0liSg0KMDBqNlE4STF0TmNmOS8vRUJXcHJNZ3JOTU5qaGw5cHR1WlB5Z29ORDVIQ1J1NFpDTTR5RzI3S1VIRG15RUFvTklaRlFhQWlKaEVKRA0KU0NRVUdrSWlvZEFRRWdtRmhsZ1I2ajk3NFhIM0pvV0dXSkJ6eTNJcUhyZXpVMmdJaVlSQ1EwZ2tGQnBDSXFIUUVCSUpoWWFRU0NnMA0KaEVSQ29Sa21kODJ5dFhHcjBHTktWT28rVUdpRzBZZ2h2Rlpva3hoQW9ibG1vOVR1WHFsZGtoa0t6VFhhMVRkVG9ySExNbWZ4ZEpkUQ0KYUo2aVZiajhPNlYyRDBydGtodFFhTTVvRmhCdmxkb2xCbEJvT2pRVENKOHJ0YXRKS1dmdExFSE5PMGVoNlFyNWFkWWxPeWkyRGI0Ug0KbmJONFVCNUtzN0M2TmhwbHVCNVl1OUJvbjFtVFk3YldlckFoaUY2MURRdWdLNURqZ0tlY0R4eGlRQjhWMnNYbjlFeDgxVUpUSDlzMQ0KQ1Exc1hEV1ZmVUh1R1hvdk9rSURjRnpJMzFKK0xlcHM0MXU3MEZnY0NXNWwwbWdWYndkZm45b3U4UWpCbkpQaEE3VUlUU1BkaDJkZA0KYU54NkRhQXBPT0RiWHZzNGpzUHFkQUdFQnpTUFM3eUpsdEJZelBDVy9DTGxGSW5BR3VUZkRPL3pYcDY2NldIQ2JTVzlZMklqWGREWg0KZWtKOHBCWk5ZNG0xZHJrRWkzWnRqVE1FSG1xTFkraXpRNkdaVCtsZUpRdkJxWjJIMkJXRkpwN1NOTXN0ME5lTitFcEMxU0RWQk5JSQ0KaFdZeUpYcU5wbktRN3FISjdtVXFBS1F3SFJLMjF4eXZEeFNhY1R3THloQnZUNWVwNXlrVE9BSlNZL2Z0UTBJdmhlWXBwYTlUVWdCUA0KVkRBeGExdnozTklzeVU2M1c3UFEvQ0I2KzJlODBGK2ZhU2V1YWpIVjNiOFhDczFkWUY3dGhkdU1wM0taSmxPeUVNMnhDRkpOa0o4Zw0KTko2OFFTUWZRN2xtdWRkRE1LbTJrczVrVHZLczE2eHBTSHI2NjZHcERHa3cxM3o1K2ZObjZ6NlF1dWtMVFRQdy8yM3YrK0lGaWxxRw0KTEdVajU4T1p0TlkvTU5IMlVvRFRKZ2hNeVhza1lNY2VyRHRCSG9GdzdDU3ZjK0I3dWZaNC9YTHF4eUZqUHg0RXBnYi9QR2FnVnJwWg0KcVBiWWlnVzc0L1hPdWhNWHZEcGRBZXhZM1d1L2FTMG1XWmlCTGl2SUlCS01kSkZEN2c1VndFWjg1YWg5bFBOdTFkVHBNby9VSWpCag0KdkpHbnVWVmFxUlExVVVOS1RSRDA1SnZpYWhlWVMvb0NWTklHc1JKb2p0ZnYxcDFJVE5nUWwweHcxaVl3ZmZvMjhOclRabXBZeDk0aQ0KQ001aVUyM05BdE1ubUNCck05bDJVdDVpWGhPWWFvc3E1MUJnbmhKTU5zdUNFTG1vWGF1TUVhcm16TkkyRkpoaGtxbndBdG1JTCsrWA0KRnZnTW9pMEtDc3h0OEtIV3RNR3NCZzlZU21CTndEeHJwcjZBQW5PZlVMdkxlM1kzaFdXWXFQR2x3RXdISDZwWGJ4cUY1VDZUaElZQw0KRXdjZU9tK2V0RVlvTEZOcDVZNTVSb0dKSjlydU5hYTJZS1FtTU04d0dZNTZTQ2t3ODhBSDIwcjVRck5XMS9FUzRCMmx3Q2dBb2NFSA0KVzZwNVJtR1p6K2g2aGdLekRKaG5yWlRuQ0dpc08xQUJnNU1oQldZNVdGQ1g1bksyWHJjZy9XUXYzVVJ5aUh4dFdCOXV4YmFDRFNiRA0KYkFMelc0STJ0STRUMTZDa09JMlZ0a3UxZ2V1djA5VmZSMnhGNzJTMmUzMTVrbmVtSlRBdmxkb040Q2EyVWxZZDRWYktNSVZ5VGpTNQ0KamdEY3kxa1ljNjdOcmpTY1Y1TU1raDlxQ0FkMllwdDVDeWZBUm14enozSnFGOHZqREwrU1BBZE1nU2RyR2E4Q004VHVkQUdyS3ZiSQ0KUGJNMHpYSm9seEl5dWNQaFVxMTBFNVVtVDlZeU5RbE1IOHNLOWpjRFg0cnNNcnhIYWRuYmpXU2VIR3NWbUVDbzFwanpRNzBaK0ZKRQ0KMnh3dHhhbHhDU2FvamVocTE3MmN0clBYTGpDQm9IRnlMUmgza21mR3o4Vno2dzdjQVphRTV0aGlLL3NXMzZ4RllBS1lKWE5VcU1kcw0KdjFOK2p6NTd4YmF4Wmprb3RwK0tMT2QrcmsxZ0FOeWdyZWd2RmpIcjVmSmF2YnIvSjdPeFh1REhrT3dncFRIV0tEQ2dFWDJoS1RFRA0KSUJadi9kYzB6VloveW5JamRTUW9hZ2VKU1Vjakt4Y1lvRzMzNXNobTNpbTErMHlwWFcyd0sxWWpsTkFJVDFkK0FBK0dWdFI0TUlFdg0KTVZvT0RLOUYzVlhYalJTWTdzRkFUbFNwWnp0YThMTjFCMHFGQXRPQkJaMldhYllWZjRmVWxyb3B6aHdLekJrdGx5VFMwdmNLN1lLUw0KRDhLcUVnck1HZTFvc1FhTmRRZFdSSXQvS0RDK2FSVGFUTEg1enhwVUswMGRZenZnSHdyTVU3NFRuZTI5RDBFdmhYWTFUTWhXb2MzYw0KYUFTa0g4YVBBdk9VVnFsZExLSzNTbTJucHJYdVFBSTB2SjRIL0VPQnljTmp0cXNETkRSaGJvSkdUeVUwajI1MkNzdzFQOG02RGhtcQ0KRlJVUElnWG1HcVN6VUdESUlCU1lhN3ltaEpBTVVHQUlpWUFDa3c4dDF6TEpDQVZtR0kwMG1VWW9NTzZod0F6VGlxOVN0U1FURkpoOA0KTk9KcmZ6d1pnQUl6VEd2ZEFWSW1GQmhDSXFEQURITlFhSk5yb2dxZ3dBekQ0Q1VaaEFKRFNBUVVHRUlpb01BUUVnRUZocEFJS0RERQ0KQ2dSeE45YWRtQWlLQSs3eERRV0dXT0N0T2c5Q0FqaFhrNlZpQ1psSUl4UVlRdUtnd0JBU0FRV0drQWdvTUlSRVFJRWhKQUlLekRBYQ0KTmEzK1VHaVRaSVlDa3c5bVFGY0FCWWFRQ0Nnd3d6VFdIU0JsUW9ISlIydmRBYkljQ3N3d2pYVUhTSmxRWUliaFFVVmtFQXBNUGxqMQ0KOG96V0FienFVR0NJQlM4enZBZGlhWCttYnBRQ1EwZ0VGSmhyVkU2dUluVkFnYmxtWjkwQlVpNFVtR3MwRnFQTUk2c0VDa3dlUGxsMw0KZ0tTQkF2TVVMZS9OWHFsZGtoa0t6Rk4rVldyWFU2WXlqeGE4QVFYR04zOGZyNjhUdDlsSUhRS3owV2lVQW5ObXA5U3U1b0wvSURvQw0KVThOSmFTcmhBUXJNbVhkSzdlNlUyZ1d0cFBmcXVVeFpHYURSYUpRQzA2R1pxdEU2YmRzNzMybzBTb0hwMEZyc2ExUERXc01WRkJoZA0KZS8xbnhiWTF3V2Z5MXJvVEM5aG9OVXlCRVhtajJMYlhodzZmaWRlK2c3MVd3MnNYR0c5VjVNazBWTll2WU0wQ28yMy8vNmpjZnVEMQ0KOGZxbzBDNCtINCtaMjZwN2JkWXFNTWp0U2gyL3VDUlhMR012T2dLai9mbG9vZXJBV2FQQTdFVS8xdkMzY3Z1NWdNbjZoWFVuSWxDZg0KcE5ZbU1EQXpjc3ljdVUwWmpSU1p3RmI4Skk5cU9uQWVXSlBBMUx6QWg5MytqMUxiTVBmMlNtMm5KTXY0cmtGZzlzZnJWY2Izc3pCaA0KRHNydGwyNmFaWnNNYXhZWXhCSGVaMzVQeTdXTGR1bWlVb1VtcStWUW84Qmc0YWR1eTQ1ZzZZYUZXYWI5OEtCOXVMSDN5dTh6QlpVeQ0KU3Zlb1JXQjJvcGR0UEpYWHh1K2ZpNCtueTFMYldLeEhIN1MzUjRGcHBETzNTa3REMzF0MzRNaXo0L1Z2cHZmQ1F3c1ROS2RXemVYbA0KSEVWTFlHcjJTQTFSaW0yZmV5czBIdDR3MWorSnp0NGZ0R2x0UFR6aVVjT1V4blByRGx3QTRiV1lzTjdKMHdjYm1kcklxR2dqMm1paw0KVzR0WnJVSHZRb0ZaQmg2S2czVW5CaWloMlBjYktmakJud3NGWmo3WXExOXFDbndPajlrcW9jRE1wN0h1d0IxZ0ttcEYvMWNMQlNhZQ0KM0o2aHVSeWtNeG1yTTRzc29jREVBVE9zc2U1RUJEQVoxeTR3MzBqbmFVdXlwcVBBVEFjYndqelc2N0x5bXBVQUpyaWtHd1VwTU5OQQ0KUU5CVHVkZEwxaW8wemVscks5UXdXZkN5WHBuQzJvU21IMHhPcG1Vb01PUEE5cTJ0N3RkYWhPWXk4eUtaZFVDQnVVWXJ4YU1VOERDMQ0Kb2xoWnhaaWhOS1ZVRTk4TENzd1p1R0JMRFVTbXBwRXV1T20xNHVjWTJqbDlEUVdtblAwZHVVR2VWeTBtV2k2cllMVUNnMXlySEdmRg0KZXdCQzB4eXYzNDM3TVplY21lTGZyMGxnMW1SeXhkSks5K0JaYk91ZWkwbGNyR2FCZ1lEZ0F6MFk5OE1USDA1WHlldWJ1Uk5ma2d4dQ0KN3dLRE9BazhJSitFSnhXbkpLeHZRQ3RsZU5SK2tHVmpuQ1NER3dKVHltNUJVaVpONy92Y0JVWlNPMlFXUCt2ZU5Rekp5MXQ1YWc3aA0KKzBiU3BKM0FaSUlHMlNkb1N3MEtERmxDV1BPTXNUbGVYMTM4em5YMnhKZWZQMysyN2dNaGhBeXhrVzdDYlU0L3Z6ajlqQ3ZudWhxKw0Ka3NQcGUwejQvNTErRHBmbnhHeDFhSlVSUW5JQ0JRRmwwWnkrV3Rkcm1jTFhjaTZKRjl2ZnNDMnJQWDA5Sk91VkU0S1NnWS9DdzJCNw0KQXc5WXNITHc5YStCNzEwdmhRa1pZQ09kRXRsS0daRThTNzQ5WGJlQ01nakp0MUpwUkJsS3BvYTAxVks1RkxDNUI5WUVhK2dnWjR1SQ0Ka0JMWUNwWEpVc2FxWC80aUZhUXowVjNtZzJBTjNRTVBaWHU2RG5yZElTc0Z1WGxib2RjakY2L2syakNGd1luRUFUZUtoMHFtTG9ZZQ0KeWtBVlZoSEpDcFRLVG95UDZDRlBHREk0aXk2aFNDV3pIc1lVRUxmZWtjQkd1bWVCS3hWZnZKZnozbWxrd3Uya0lHT1NTb1lNK1lPTA0KdG94SVVwRGh0UmV1Vm1vQjQ5aXZPV0JlZkpGS2hnelJ0NHlBK1lOS2tyS1J6dEtsWXFtZi9wbTBKbkpNSlVPbTBIOVFpMXVPazhucw0KWlg2R0kvRlBYNDZYRm1pYURKVU1pZVZ5T1U3WFd0bHNoRWNIazJ1Q0RLc2ZVa29sUTViU2Q2MVI0WlJEeWZXQVNUa2dVeTNzbFh3dQ0KQ2dsQVZESWtKWDJGby9MQWtydFF1WkM1aEJWdlV0bWxraUZhaEFlV3gvZmtnY3FGcENMSWJwTHpMS2hraURZaFJWcmQ5N3RTTnNLWQ0KQzlFQmJqUnM0dDR1YVlSS2h1UWkrSDZwYk5MQndyWkVtN0NKK3h1WldUT1JTb2JraHNwbU9kaEErYWQxSjhpcXdQT0dVd1ZmeHI2UQ0KU29aWUVaUU5Zelp4N0lWN1hZZ05XRFZEWnFOaU5WUXl4Sm9RczJFMjJuMTRMTWM0djUyK2hwTXJaZVRuUzhKcG00SE42UUowUlE2RA0KNTNDeSs0eEtocFFDZ3Rlemx1TXJZQ1ByRE82anVrUXJYZXpwbnJLWXk5eXptY0lKbjNoZUcxbGZpUjY0enlaVkRmQ2taSktrMHltQg0KQjI1eituNGo1N1BKZzVYRUE1Mm1FWmJqWE5XY1dVdjh4VnMxY0NpODluUmRzcEhPQlh6ck5Nd2FRTXI4WFVYalNjbVV6SkxqbE1ONQ0KNTdpNFBPK0ExYzdxQVhVcm1HeTFzd3c0U0tkaytyRkdmUDkrOEs5OUEwVnowM1ZHSldQUFg2ZHJhRUxkU0plamppWDUycGJqRU1oRw0KMXVzK3EwM0JJSnR3SzM1V0txbjVJR2NacjIzakxKN1RVVThUbFV6WkhLU3JlTHk3K0gydFZ0RWxzN0paS2dBdTFsb1V6T3o5RlJXRA0KRlZ4NHB2ZFNSN1pnS3lOYkVxaGtmTkszaWtEdFNtZHRpdVpmNnc0c2hIdWdwck05WFpCbnp6RWN4SjJ4UXJ0eWdWTEoxRUZmNmRSNg0KMGlFVXpUUFJ5VEFxaWIxMUJ4WkE1VEtmRU1OcHhXK2lFRnlBVjhZZ2xVeDl3RFh4NHZSOWJiNWZXUGcxcjJnd1hsNWRKM1NMcGFHUg0KYm1YejBiWWJzOW5LaGFGRUpWTTNmZDl2SzM0dHBENTlKVm9iSGcwQ3JsN1NzNWZ1T2ZjWWw5c0tsY3hxYVU1ZlcvR3RiT0FHaFBLcw0KTGV2TVk3cTJ5Wm54S3dGS0JxdERiNG9HYzh0R2VsbUVWRExyb3psOWJjV3Zza0hXMlU3cW1lQ1FUZVl0Nk10OVRQcEEwV0Eva2JjVg0KYmlPOTFReVZ6SHBweFBkZWpIY3l2dVBhR3p2ckRrUkNCWk1Qck5wUkRjR1RFYkxwLzBBbHMyNWdLU0ZtMDRyUFZjM3ZVa2NpZ0tjSg0KSkpSL0lmbndWcUxtU2N5VVNvYUFSdnp1dGRtSnY1VkFIMi9ISEhqcmJ5MTRXODA4UWlWREFyQk9zYkw1M2JvamtjQnR0aGUvNVVvYQ0KNnc1RThKMTFCMWJNWHFoa1NBVzA0ak9qWlNjTHp5RTN4RXRSVkJ6RDBGcDNZc1c0M1lORUpVTXV3Y01NaTlYVGlnWWJHSGZpYnpYag0KS1EyYmNSZ3lsU2RWT2Foa3lCRHQ4WG90dm5ZZDc4VGZhc2JUcHRMV3VnUGtZVFhwWWVYN1pOVkZKVVBHMkVzM0NYcnhBMk0xczdYdQ0KUkNSZWxNeFAxaDBnRDNoUU1LRHQvMEFsUTI3aExYVVMvZlhrMXZFeWFkUjZ1QmpSZ1NzWkVvV25IY2VJY1hoU01sNXdHM1N1REd5Qw0KTFgyYndldkxYMURKa0h2QWlrVVJSQStiTmEvcUpoV01GMWNaS1lmTGM2UnVzWkd1WEpFV1RlLzdnM1F1c3NGak9LaGt5QlIyNGlmYg0Kakt1WnRQeG0zUUV5aTROeSs1Tlh0MVF5WkFydDhmcGJmQnlFMWdpVkRDSEZRQ1ZEcHJLWDh2M0J3RXN3blpCVlFDVkRwdEphZHlBQw0KeERzWXJDYWtBS2hreUZROFRkcWFBVTlDU0FSVU1pUUdMenVPc1pKcHJUdEJDS0dTSVhHMDRrUEpiS3c3UUFqcG9KSWhNYlRXSFpqSQ0KeHJvRGhKQU9LaGxDQ0NGcVVNa1FRZ2hSZzBxR3hPQWx3OHhEM0lpUVZVQWxRd2doUkEwcUdVSUlJV3BReVJCQ0NGR0RTb1lRUW9nYQ0KVkRLRUVFTFVvSkloaEt5RlZud2N2dWVkTC9vL1VNa1FRdGJBVzZHQ3lRVk8wMzBaZnFDU0lZUVFvZ2FWRENHRUVEV29aQWdoaEtoQg0KSlVNSUlVUU5LaGxDQ0NGcVVNa1FRZ2hSZzBxR3hQREN1Z01UK2MyNkE0U1FEaW9aUWdnaGFsREpFRUlJVVlOS2hzVFFXSGRnSWw0Tw0KVnlPa2VxaGtTQXhlWWpML1dYZUFFTkpCSlVOaThLSmt1SklocEJDb1pNaFV2anBlWDF0M1lpSmN5WkJMYUhnWVFTVkRwdEpZZHlBQw0KVGlqa2tsYTZFdlJiNlZVSWRnb01QamNWcGFsa3lGUzIxaDJZQ1BmSWtGdnNUNWRuNExiKzA3b1RVNkdTSVZQNTNyb0RFMm10TzBBSQ0KT1VNbFE2Yncxcm9ERWJUV0hTQ0VuS0dTSVZONGI5MkJDQmlQSWFRZ3FHVElQYmJXSFlqZ0Yrc09FRUtlUWlWRDd2SFJ1Z01SN0swNw0KVUNGZVluR2tVS2hreUMwK1dIY2drdGE2QXhIUXJVZFdBWlVNR1FON0NkNVlkeUtDSDYwN1VERkltYVZTSkxPZ2tpRkRZTFBYcjlhZA0KaU1UYnFndGdUNDhIZHhRTURpcVpjbWlzT3hBRGxRd1o0bC9yRGtUeWszVUhab0tKMjRPU2VYZThkdGFkSUk4MDFoMklnVXFHWE9MUg0KWXQxWmQyQW1uajdyUm56RnZHckdnMkh5Q0pVTTZZTkp6MHNSeklEbldFeHIzWUVJc0NHM3RlNEVjYldsNEFFcUdSTDRuM1VIWnVJeA0KRmhOQXRlZy94RWV4UTFqUGpWRFJXT09wK3NZRFZETEVWYkc5Qzc2ejdrQUNQb2tQSlFPZzBMMmNLVlFqVy9IbmFhQ1NXVG1ZTkR5bA0KS2ZmNVdlcXdxdmZpcDJ3UEpqZzhNKzZzNlFwQXhxZW5qZEdQVU1tc2s4M3grc2U2RXd2NFcrcVo2T0F5UXptY1Y5WWRtUWlNRXNUdQ0KOXNiOVdCdmVNajRmb1pKWkg2MzRjYytNMFZoM0lERllIWGhSTWdBV05aVGpKK3VPckFSUFdZaFhVTW1zQjgrdXNUN2ZTSDNISzJNUw0KOGJTYUFkaXNpOHcrejRrWEh2Q2FrUE1JbFV6OXRPSi81Ukw0UVp4YmRUZUErOCtUa2dHSUpUWGkvempqRXZHY2tQTUVLcGs2Z2RCNw0KS3d0ekQxak5OYnRuc0RwRDVZSjMxaDJKQktuTnNMYWZINitEYlZlcUFjKzVxdzJYdDZDU3FRZFlQbnR4bU9JNGdiVzRaWGJTR1FnZQ0KeHhDSkpOanoweGozd3pNMUdvZFVNczZCaThWTCt1dGM0Q0tyZVFWelNTTitNNG5nbHNXcWhzb21qaXFWUzRCS3hnL0lrOTlLL1VxbA0KRDRMOHRjWmd4b0RiRElyVjg2UVRsQTJnRzIyY3F0eGlZMURKbE1sR09vWGkxWFdTZ21kU1h4YlpWREQ1d0VWWWcwRVI5bVBoV0lPdA0KckhkTUF6dnhGM2RiQkpXTUhZMTBjUlI4cmQ2YWlZQ3VsZzdFb0RaU1I5bzV3RFBlZHdPdXhRMEtRM0VuNnpJV244eG5WREx4YktSeg0KWGZWcFRsL3grMURiaVlvam50ZkNuZVI5UWxXRFdoUk5uMHQzSU1vRTdjVzNlM1FqM1dwdFZTdVZlM2hTTXU0M0paRlJVQ2FHaFJlSA0KZ2FJNVNCMnVzMXU4a1dGbGlrMnFyWFRLcHdRRjlFTE9IZ2h2KzVwTThLUmtTSjJzeFcyeUJMak9EdUk3R1dBdXIyVDZaQTVqNWRENw0KK1NDM2t3NDJwNnYvODVyY1dsbWdraUZXSUJETW5lTFRnU0pHcHBibndxYmFmQzFVRXFXQTFkN0R5cE5LaHVTR2dmMzVISTdYRjFKWA0KcVNCU09WUXlKQ2ZjTTVHR1Jyb0FzOHZ6UmNpNm9KSWgybkRsb3NQK2RMWENWYzNhQ1lrenJaVHpMRFJDZHhsUkJpbXB0UndzVmpLTg0KVkZTeGwwU0RvcXE3MC9kRmJuU2xraUdwK1U3cU9CYlpFN0FZRWF1cHVnWVd1ZUtMaTU5YktXZC9YaU9ub3JaVU1pUUZmV3VLMklFTQ0KTkV3OHRSeFFSNFp4bGZaUEpVUG1Rc1ZTTG05UEYxYzJkWEZQNXRvODNaakU0NHFLU29iRXdMSXZ2Z2dyRzhac2ZEUFZvQ3VoSWtLZg0KaDcweVZETGtGZ2plNzZUUWdDS1pUSWpaQUxyUy9PREtMVFpBSTFReTVBSllUSmlFcUZUcUpialNVTXdWRTFncEthK2tZMm5LUHlwcA0KbEJMOGY2aEhTQ1d6WG1xb2Vrdm1BME9pT1gwUGhiT1hjaWFuTlpJcUt4TnRsREtPcURtM3BaS3BIMWcybjA0WFZ5aGtDRHdYL1RweQ0KYXpqVzJ4cHNvTVRuM0NadU4zVjdTM2xCSlZNSG9SdzZyb05sUjBnVmZEaGRBU3FkTk9UWW9GeWFaK0lsbEF3MEtpdVhsZ2xXSVFjNQ0KbjZWUjJnTkUxc0dsMG9HdmZTdE1JTGdIanREK2NQZXYwZ1BYMis4Rzd6dkVCa29HRHd5MDYxYW9iSmJ3MjhEdjJ0NzNCem12TXFncw0KaUdmdy9JWUVnZ0RpT25DNWJXVjl5UVFJMXUrbEhKZDBLMTAyb2VXOER1OEtGT3hqZHRtbHBVSUlJVEZnY3QzTDhENnFqWnhyck9Hcg0KUjJNV2lxVHRYUjRvWWw1blRJWVFvczFCcG0zaXhXcG8wN3Z3ODR2ZS82VmFJUVd2dytGMFFVSCsxZnVlSk9UL0xrdVJ4bXpERWhjQQ0KQUFBQVNVVk9SSzVDWUlJPSIvPg0KICAgPGltYWdlIGlkPSJPYmplY3RfeDAwMjBfNyIgeD0iMCIgeT0iMTg2NiIgd2lkdGg9IjIxMzMiIGhlaWdodD0iMjY3IiB4bGluazpocmVmPSJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQWdBQUFBQkFDQVlBQUFFYnVQOHBBQUFBQ1hCSVdYTUENCkFBc1NBQUFMRWdIUzNYNzhBQUFHSUVsRVFWUjRuTzNkNFphYU1CQ0dZZlljTDJxdnBEZlZpN1psdTdaV0U1Z2hNMGttOHo1L3RrWDgNCmlCcENDRUZ2UHo1LzNyZkVidHY5OSt2LytOaSsvdTRlLzk3LzdvNGV2L0tjMThldlBFZnkrRU50MmZkemJuLy84L2hiKzdkMFdldmoNCmxwbWw5VjZXMzhxUE5IcitaS1RMQnRXcW02cXdyeUcxNE5Kenp2SjdlTjBWdHUxcEYzaDJ0aXpLTG5DMFczd3Y5OWtGU3FRMTVLelcNCnVPMEMza2VCMnB2eCtweXpOMDJpVU5WcnkyLzBBODZxamtVcjNidS84RkJhOXZ5Y2JUdnBCMFJwMkdyL0ZpeXpid1FuYU5nZXkvWWwNCjk2T2F1RzNLZm9Ca3c5S2NEdjZyK0pXR1VkOFBpTElMQ0hlTFB2MEFUWS9Rc011czJ3Vzh6OWJPWHFEMERaTDR6cnVYMnFFWDZmc0INCjJkM2VhbCtwSC9HOFhMcnNMUFBLZGp3eXIyeG5SR2FKZEwyRGRkOFBnclVtUjN1d3ZMTHNhUG5WOWJUcnpxcndBWDc4L25zL2VtL1ANCktzWFdxeFBRcWxlbGFLMm9uVFB2d3ZXT2xyOGZBbXEwNnoydnl5R2diMmFKK0JBZ0NkQ3UxMnZQMHBUcG9UUXkxNXJaeWRkcFR2R0INCjFRNEJVaDRmNE1TSEZaOURBR2NCL3dZUURET2J5MWxpY1JiQU9FQnVheDBDb1BaK05XQzJIdmZFaDRxdW1TVUdod3BhZ09Sa0k0RWoNCkIwZ21Ib2dabGluZGptQzkrVnVBV3RQYXNtN0VRNERIZHJZSUZRQ3U1cThBUFFkM0lod0NqTGRUbmhQMDZrb3p6Rm1BVCtiWmRrbzQNCkJLQkdkakdvMTNqNDZONTFoRXpOZGdUcnJkVUN0SjRGZUdUT2NFamtFSUNhdFNwQTYxbUFSK2JraDBTdUJVUTVDeWpoTE9DYS9lM2cNCkd2Z2Z6QWNBRWt0NUJBRHd4NjNhZDMybzlTMmw2N2FzNTVIWjYvVkV5ZXoxdm1mSmxOSnMyekh6L0VKQXp4R1RIcG1ydlI0eVkyUmENCmI5c29rMU1BSURFYUFBdWE3dnBzbVZHNjFwRXpDK3Q5WFlrWWVUcjNqUWJBd2dKZHdjdnJrbmxwdmVvdTJmbjEwQUFBaVoxZkJkRFENCmRFdXNNMmNiWFkrU0dibHJIU1d6OWJPVWNya0tZRkdBSHBrUnVvSms1c3owMkxZR3B3QUFTbWdBWmhYNXlvSkg1bUtuQUZ3RndMSFINClZ3R2laQVk5QmVBcUFJRGh1QmNnZTJia3J2V01tVklYdXVzZW1kd0xRQ2FaUFRLdHQyMlV5ZmNCQUlreEJnQWtSZ01BSkVZREFDUjINCi9qdkJzNDFhZTJSR0dXSE84QjVGcVVkSHVSSzlNay95NkFFQWlkRUFBSW5aelFNWWZaMDFheWF2WjB5bWR0MVJtU2Q1OUFDQXhHZ0ENCmdNUm9BQ3lNL0NZa2oweXVBdGl0TjJQbUV4b0FJREVhQUNBeEdnQUxFVWFETlpsY0JVaVRTUU1BSkVZREFDUm05N3NBbzc5d2NyYVINCjF0Vkd6VmQ3UFI2WnJlOVJiVjBwcmdJQTBLQUJBQkt6KzJXZzBTUGhFNCswdW1ieWV0YkoxSzVya0VjUEFFaU1CZ0JJakFaZ1ZxdmQNClg5Q1NWOHRjN1NvQTl3SUE2SWtHQUVpTUJtQldvNitxak1xTU1tSy9TQ1lOQUpBWURRQ1FHTDhMVUZzdlN1WnE3MUdVZW5TVUs4RzkNCkFBQkdvd0ZZMEg0YzRDZWZJY0h2QWtUUExLeFgzZm1EdnA0cE03WHJqc284dXdydzQvTW5Cd3NBQUpKaENBQUFnSVRvQUFBQWtCQWQNCkFBQUFFcnFwNWoyWGFPWXRTM05IWmtaNTdTUGZTMDB1NVp3N2MrUjdHU1V6YzkzVTVIcTFuWmEwayt3aWxMT2hqSXdBQUFDUUVCMEENCkFBQVNhdjlOc0FqM1FtYk85Q2lqUjI3bWNwSTVkMmJtdXVtVjYxVldheEhLMlZCR1JnQUFBRWlJRGdBQUFBblJBY0FjdkdZd1cxdXQNCm5GRm1nek83M2k1UGs2bkpEWENIeXRmM3BBY29KM2NCQUFBQU4zUUFNQVYrd1FoV3BPZE8wdnFtR2NmUjFPRW81Y1M2NkFCZ0N1SmgNCnVkRXlsek5JcG5WZDhxcWJVY29aNG00RllhYXE0eE9rdm5NWEFBQUFVQ2wvRmZBdXdnU20zV3JsWEdoaWtHckNqWmNJNVl4UzN3RzgNCkM3ei9NZ0lBTjZyaHRvRTdVWlJ5cXF3Mmd6bkNySFZOcGlZM2F6bEgveTZMTnRjeWo3c0FBQUNBRnpvQWdNYkFzM3JWblJLVERUVlcNClJTaG41c2wxSHJtVFRZUnJ6aDA5S3RnMENYREdIWERHTXBWTTltRjJ5ZlBLalZKT0R4NHptRDFFZUM5M1VjcUpOUVN1YjR3QUFBQ1ENCkVCMEFRR1AwY0o4VTViUXplb0laa3dETk12a3E0UC9SQVFBQUlDRTZBQUFBSkVRSEFOQ0lNdUdIY3RxSk1rRTFjem41S3VCTDZBQUENCkFKQVFIUUFBQUJJcS94YkE2SzlnalBBZCs1cE1UUzR6ZysweU5ia1I2cVpIWnBRWnpLdDk1cHJjMWNxcHliU21IUzZQVUU3dUFnQUENCkFCcDBBQUFBU0tqOXE0QW5tOVZJcG5PZVYyN21jcEk1ZDJibXV1bVZHK0h1ajEyRWNuSVhBQUFBMFBnRnlDM3dVS0NDczd3QUFBQUENClNVVk9SSzVDWUlJPSIvPg0KICAgPGltYWdlIGlkPSJPYmplY3RfeDAwMjBfOCIgeD0iMCIgeT0iMCIgd2lkdGg9IjIxMzMiIGhlaWdodD0iMjY3IiB4bGluazpocmVmPSJkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQWdBQUFBQkFDQVlBQUFFYnVQOHBBQUFBQ1hCSVdYTUENCkFBc1NBQUFMRWdIUzNYNzhBQUFCczBsRVFWUjRuTzNjc1kzY1FCUkV3VFhHWmY0ZW82VFB6WUp0dktvSUJzUy9wNVp3MEhudTYvMkYNCm5mVUQxbnlBOVFQV2ZJRDFBOVo4Z1BVRDFvNGRFT2NEckIrdzVnT3NIN0RtQTZ3ZnNKYmZBWFg1bjRBNkJ4RG5BT0ljUUp3RGlITUENCmNRNGd6cjhEeENsQW5BT0ljd0J4RGlET0FjUTVnRGdIRU9jQTRoeEFuQU9JY3dCeERpRE9BY1E1Z0RnSEVPZjNBU0RNbndBUUpnQVENCkpnQVFKZ0FRSmdBUUpnQVFKZ0FRSmdBUUpnQVFKZ0FRSmdBUUpnQVFKZ0FRSmdBUUpnQVE1djhEZ0RBTEFNSUVBTUlFQU1JRUFNSUUNCkFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUUNCkFNSUVBTUlFQU1JRUFNSUVBTUlFQU1JRUFNSUVBTUxPYzEvditoRUF3TGY4RFFBQWdnd0FBQWd5QUFBZ3lBQUFnQ0FEQUFDQ0RBQUENCkNESUFBQ0RJQUFDQUlBTUFBSUlNQUFBSU1nQUFJTWdBQUlBZ0F3QUFnZ3dBQUFneUFBQWd5QUFBZ0NBREFBQ0NEQUFBQ0RJQUFDREkNCkFBQ0FJQU1BQUlJTUFBQUlNZ0FBSU1nQUFJQWdBd0FBZ2d3QUFBZ3lBQUFneUFBQWdDQURBQUNDREFBQUNESUFBQ0RvRDJzQkZETWcNCnBRL3BBQUFBQUVsRlRrU3VRbUNDIi8+DQogIDwvZz4NCiA8L2c+DQo8L3N2Zz4=">
<script>
(function(){
  var t = localStorage.getItem('phpdg-theme') || 'dark';
  document.documentElement.setAttribute('data-theme', t);
})();
</script></head>
<body>
<div class="app-shell">
    $topBar
    <div class="app-body">
        $sidebar
        <main class="main">
            <div class="container">
                $content
            </div>
        </main>
    </div>
    $statusBar
</div>
<script>
const PHPDG_INDEX = {$searchIndexJson};
const PHPDG_ROOT = "{$rootPath}";
// ── i18n / language ──────────────────────────────────────────────────────────
const translations = $translationsJson;
const languages = $languagesJson;
const availableLanguages = $availableLanguagesJson;

let currentLang = localStorage.getItem('phpdg_lang') || '{$this->settings['language']}';

function applyTranslations() {
    const lang = translations[currentLang] || translations['en'];
    document.querySelectorAll('[data-i18n]').forEach(el => {
        const key = el.getAttribute('data-i18n');
        if (lang[key]) {
            el.textContent = lang[key];
        }
    });

    const searchBox = document.getElementById('search');
    if (searchBox && lang['GENERATOR_SEARCH_PLACEHOLDER']) {
        searchBox.placeholder = lang['GENERATOR_SEARCH_PLACEHOLDER'];
    }
    const sbSearch = document.getElementById('sidebarSearch');
    if (sbSearch && lang['GENERATOR_SEARCH_PLACEHOLDER']) {
        sbSearch.placeholder = lang['GENERATOR_SEARCH_PLACEHOLDER'];
    }
}

function changeLang(newLang) {
    currentLang = newLang;
    localStorage.setItem('phpdg_lang', newLang);

    const langData = languages[currentLang];
    if (langData && langData.direction) {
        document.documentElement.setAttribute('dir', langData.direction);
        document.documentElement.setAttribute('lang', newLang);
    }

    applyTranslations();
    updateLanguagePicker();
    toggleLanguagePicker();
}

function updateLanguagePicker() {
    const langData = languages[currentLang];
    if (!langData) return;

    const current = document.querySelector('.lang-current');
    if (!current) return;

    current.innerHTML = langData.flag +
        '<span class="lang-name">' + langData.native + '</span>' +
        '<span class="lang-arrow">▼</span>';

    const dropdown = document.getElementById('langDropdown');
    if (!dropdown) return;

    let dropdownHTML = '';
    availableLanguages.forEach(code => {
        if (code === currentLang) return;
        if (!languages[code]) return;
        const lang = languages[code];
        dropdownHTML += '<div class="lang-option" onclick="changeLang(\'' + code + '\')">' +
            lang.flag +
            '<span class="lang-name">' + lang.native + '</span>' +
            '</div>';
    });
    dropdown.innerHTML = dropdownHTML;
}

function toggleLanguagePicker() {
    const dropdown = document.getElementById('langDropdown');
    const current = document.querySelector('.lang-current');
    if (!dropdown || !current) return;
    if (dropdown.style.display === 'none' || dropdown.style.display === '') {
        dropdown.style.display = 'block';
        current.classList.add('active');
    } else {
        dropdown.style.display = 'none';
        current.classList.remove('active');
    }
}

document.addEventListener('click', function(e) {
    const picker = document.querySelector('.language-picker');
    if (picker && !picker.contains(e.target)) {
        const dropdown = document.getElementById('langDropdown');
        const current = document.querySelector('.lang-current');
        if (dropdown) dropdown.style.display = 'none';
        if (current) current.classList.remove('active');
    }
});

// ── Method / function expand ────────────────────────────────────────────────
function toggleMethod(id) {
    const details = document.getElementById(id);
    const icon = document.getElementById('icon-' + id);
    const wrapper = details ? details.parentElement : null;
    if (!details) return;

    const open = details.style.display !== 'block';
    details.style.display = open ? 'block' : 'none';
    if (icon) icon.classList.toggle('expanded', open);
    if (wrapper) wrapper.classList.toggle('is-open', open);
}

// Auto-open method/function targeted by hash (deep link from sidebar search)
function openHashTarget() {
    const hash = window.location.hash;
    if (!hash) return;
    const target = document.querySelector(hash);
    if (!target) return;
    if (target.classList.contains('method-item') || target.classList.contains('function')) {
        const details = target.querySelector('.method-details');
        if (details) toggleMethod(details.id);
    }
    setTimeout(() => target.scrollIntoView({behavior:'smooth', block:'start'}), 80);
}

// ── Project tree (legacy in-page) ───────────────────────────────────────────
function toggleFolder(element) {
    const treeItem = element.closest('.tree-item');
    if (!treeItem) return;
    const children = treeItem.querySelector('.tree-children');
    if (!children) return;
    const open = children.style.display === 'none' || children.style.display === '';
    children.style.display = open ? 'block' : 'none';
    element.classList.toggle('expanded', open);
}

// ── Homepage index section toggle ──────────────────────────────────────────
function phpdgToggleIndex(titleEl) {
    const section = titleEl.closest('.index-section');
    const table   = section.querySelector('.index-table');
    const open    = section.classList.toggle('open');
    table.style.display = open ? 'flex' : 'none';
}

// ── Sidebar dir toggle ──────────────────────────────────────────────────────
function phpdgToggleSbDir(el, event) {
    if (event) event.stopPropagation();
    const next = el.nextElementSibling;
    const open = !el.classList.contains('expanded');
    el.classList.toggle('expanded', open);
    if (next && next.classList.contains('sb-tree-children')) {
        next.style.display = open ? 'block' : 'none';
    }
}

// ── Sidebar search (uses inline PHPDG_INDEX, toggles tree/results) ──────────
function phpdgInitSidebarSearch() {
    const input = document.getElementById('sidebarSearch');
    const results = document.getElementById('sidebarSearchResults');
    const tree = document.getElementById('sidebarTree');
    if (!input || !results || !tree) return;
    if (typeof PHPDG_INDEX === 'undefined') return;

    const TYPE_BADGES = {
        F:  {color:'#4f46e5', label:'F'},
        C:  {color:'#4ec9b0', label:'C'},
        M:  {color:'#10b981', label:'M'},
        fn: {color:'#0ea5e9', label:'fn'},
    };

    const showResults = (items) => {
        tree.style.display = 'none';
        results.style.display = '';
        if (items.length === 0) {
            results.innerHTML = '<div class="sidebar-empty">—</div>';
            return;
        }
        let html = '';
        items.forEach(it => {
            const b = TYPE_BADGES[it.t] || TYPE_BADGES.F;
            const sub = it.c ? (it.c + ' · ' + it.p) : it.p;
            html += '<a class="sb-result" href="' + it.u + '">' +
                '<span style="display:inline-block;min-width:20px;font-size:9.5px;font-weight:700;color:' + b.color + ';font-family:Consolas,Menlo,Monaco,monospace;margin-right:8px;">' + b.label + '</span>' +
                '<span style="color:#e5e7eb;">' + escapeHtml(it.n) + '</span>' +
                '<span style="display:block;font-size:10px;color:#6b7280;margin-left:28px;margin-top:2px;font-family:Consolas,Menlo,Monaco,monospace;">' + escapeHtml(sub) + '</span>' +
                '</a>';
        });
        results.innerHTML = html;
    };

    const showTree = () => {
        results.style.display = 'none';
        results.innerHTML = '';
        tree.style.display = '';
    };

    let timer = null;
    input.addEventListener('input', e => {
        clearTimeout(timer);
        timer = setTimeout(() => {
            const q = e.target.value.toLowerCase().trim();
            if (q === '') { showTree(); return; }
            const filtered = PHPDG_INDEX.filter(it =>
                it.n.toLowerCase().includes(q) ||
                (it.c && it.c.toLowerCase().includes(q)) ||
                it.p.toLowerCase().includes(q)
            ).slice(0, 80);
            showResults(filtered);
        }, 80);
    });
}

// ── Init ────────────────────────────────────────────────────────────────────
applyTranslations();
updateLanguagePicker();

const initialLangData = languages[currentLang];
if (initialLangData && initialLangData.direction) {
    document.documentElement.setAttribute('dir', initialLangData.direction);
    document.documentElement.setAttribute('lang', currentLang);
}

phpdgInitSidebarSearch();
window.addEventListener('load', openHashTarget);
window.addEventListener('hashchange', openHashTarget);

// ── Copy source helpers ──────────────────────────────────────────────────────
const COPY_SVG  = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="13" height="13"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>`;
const CHECK_SVG = `<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round" width="13" height="13"><polyline points="4 12 9 17 20 7"/></svg>`;

function flashCopied(btn, isIconOnly) {
    const orig = btn.innerHTML;
    btn.innerHTML = isIconOnly
        ? CHECK_SVG.replace('width="13"', 'width="15"').replace('height="13"', 'height="15"')
        : CHECK_SVG + ' Copied';
    btn.disabled = true;
    btn.classList.add('copied');
    setTimeout(() => { btn.innerHTML = orig; btn.disabled = false; btn.classList.remove('copied'); }, 3000);
}

function copySource(fileId, lineStart, lineEnd, btn) {
    const url = '{$generatorPath}?action=get_source&file_id=' + encodeURIComponent(fileId) + '&line_start=' + lineStart + '&line_end=' + lineEnd;
    fetch(url)
        .then(r => r.ok ? r.text() : Promise.reject('HTTP ' + r.status))
        .then(text => JSON.parse(text))
        .then(data => { if (data.success) navigator.clipboard.writeText(data.source).then(() => flashCopied(btn, false)); })
        .catch(() => {});
}

function copyModalSource(btn) {
    const code = document.querySelector('#modalBody pre code');
    if (!code) return;
    navigator.clipboard.writeText(code.textContent).then(() => flashCopied(btn, true));
}

// ── AJAX Source Code Viewer ──────────────────────────────────────────────────
function viewSource(fileId, lineStart, lineEnd, functionName) {
    let modal = document.getElementById('sourceModal');
    if (!modal) {
        modal = document.createElement('div');
        modal.id = 'sourceModal';
        modal.className = 'modal';
        modal.innerHTML =
            '<div class="modal-content">' +
                '<div class="modal-header">' +
                    '<div class="modal-title-row">' +
                        '<h3 id="modalTitle">Loading...</h3>' +
                        '<button class="modal-copy-btn" onclick="copyModalSource(this)" title="Copy source"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" width="15" height="15"><rect x="9" y="9" width="13" height="13" rx="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>' +
                    '</div>' +
                    '<span class="file-info" id="modalFileInfo"></span>' +
                    '<button class="modal-close" onclick="closeSourceModal()">&times;</button>' +
                '</div>' +
                '<div class="modal-body" id="modalBody">' +
                    '<div class="loading">Loading source code...</div>' +
                '</div>' +
            '</div>';
        document.body.appendChild(modal);

        modal.onclick = function(event) {
            if (event.target === modal) {
                closeSourceModal();
            }
        };
    }

    modal.style.display = 'block';

    document.getElementById('modalTitle').textContent = functionName + '()';
    document.getElementById('modalFileInfo').textContent = '';
    document.getElementById('modalBody').innerHTML = '<div class="loading">Loading source code...</div>';

    const url = '{$generatorPath}?action=get_source&file_id=' + encodeURIComponent(fileId) + '&line_start=' + lineStart + '&line_end=' + lineEnd;

    fetch(url)
        .then(response => {
            if (!response.ok) {
                throw new Error('generator.php not reachable (HTTP ' + response.status + '). Place generator.php next to your output folder.');
            }
            return response.text();
        })
        .then(text => {
            let data;
            try { data = JSON.parse(text); } catch(e) {
                throw new Error('generator.php returned non-JSON. Make sure it is a PHP file served by a PHP server.');
            }
            if (data.success) {
                document.getElementById('modalFileInfo').textContent =
                    `\${data.file} (lines \${data.lines})`;
                document.getElementById('modalBody').innerHTML =
                    `<pre><code>\${escapeHtml(data.source)}</code></pre>`;
            } else {
                document.getElementById('modalBody').innerHTML =
                    `<div class="error">\${data.error || 'Failed to load source code'}</div>`;
            }
        })
        .catch(error => {
            document.getElementById('modalBody').innerHTML =
                `<div class="error">\${error.message}</div>`;
        });
}

function closeSourceModal() {
    const modal = document.getElementById('sourceModal');
    if (modal) {
        modal.style.display = 'none';
    }
}

function escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
}

document.addEventListener('keydown', function(event) {
    if (event.key === 'Escape') {
        closeSourceModal();
    }
});


function phpdgToggleTheme() {
  var html  = document.documentElement;
  var theme = html.getAttribute('data-theme') === 'dark' ? 'light' : 'dark';
  html.setAttribute('data-theme', theme);
  localStorage.setItem('phpdg-theme', theme);
}
</script>
</body>
</html>
HTML;
    }

    private function buildSearchIndexJson($rootPath)
    {
        $entries = [];
        foreach ($this->documentation as $file => $doc) {
            $rel = $this->getRelativePath($file);
            $url = str_replace('.php', '_php', $rel) . '.html';
            $entries[] = ['t' => 'F', 'n' => basename($file), 'p' => $rel, 'u' => $rootPath . $url];
            foreach ($doc['classes'] as $cls) {
                $entries[] = ['t' => 'C', 'n' => $cls['name'], 'p' => $rel, 'u' => $rootPath . $url . '#class-' . preg_replace('/[^a-zA-Z0-9_-]/', '', $cls['name'])];
                foreach ($cls['methods'] as $i => $m) {
                    $mid = 'method-' . preg_replace('/[^a-zA-Z0-9_-]/', '', $cls['name']) . '-' . $i;
                    $entries[] = ['t' => 'M', 'n' => $m['name'], 'c' => $cls['name'], 'p' => $rel, 'u' => $rootPath . $url . '#' . $mid];
                }
            }
            foreach ($doc['functions'] as $i => $fn) {
                $entries[] = ['t' => 'fn', 'n' => $fn['name'], 'p' => $rel, 'u' => $rootPath . $url . '#func-' . $i];
            }
        }
        return json_encode($entries, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
    }
}// ===== EXECUTION =====
// Run generator when:
// 1. Direct access (no params)
// 2. AJAX generation request (?generate=1) — streams SSE progress
// Skip execution only in ggui UI mode (?ggui=1)

if (!isset($_GET['ggui']) && !defined('PHPDG_NO_AUTORUN')) {
    $isAjax = isset($_GET['generate']) && $_GET['generate'] === '1';

    if ($isAjax) {
        // SSE streaming setup
        while (ob_get_level() > 0) { @ob_end_clean(); }
        header('Content-Type: text/event-stream');
        header('Cache-Control: no-cache, no-transform');
        header('X-Accel-Buffering: no');
        ignore_user_abort(true);
        @ini_set('zlib.output_compression', '0');
        @ini_set('output_buffering', '0');
        @ini_set('implicit_flush', '1');

        $generator = new phpDocGenerator($settings, $translations, $languages);
        $generator->sseMode = true;

        try {
            $generator->generate();
            echo "event: done\ndata: " . json_encode(['success' => true]) . "\n\n";
        } catch (Exception $e) {
            echo "event: error\ndata: " . json_encode(['error' => $e->getMessage()]) . "\n\n";
        }
        @ob_flush();
        @flush();
        exit;
    }

    // Non-AJAX: original behavior (CLI or direct browser hit)
    $generator = new phpDocGenerator($settings, $translations, $languages);
    $generator->generate();
}
// ============================================================================
// GGUI UI MODE - Show generation progress with AJAX execution
// ============================================================================

if (isset($_GET['ggui']) && $_GET['ggui'] === '1') {
    ?>
    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <link rel="icon" type="image/svg+xml" href="<?= FAVICON_BASE64; ?>">
        <title>PHPDG</title>
        <style>
            /* ========= GGUI-ONLY STYLESHEET ========= */
            

            body {
                font-family: 'Sofia Sans', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
                background: #0f1117;
                color: #d4d4d4;
                overflow: hidden;
            }
            .ggui-container {
                width: 480px;
                height: 100vh;
                margin: auto;
                padding: 36px 30px;
                display: flex;
                flex-direction: column;
                justify-content: center;
            }
            .ggui-logo {
                display: block;
                margin-bottom: 28px;
                color: #ffffff;
            }
            .ggui-logo svg {
                height: 24px;
                width: auto;
                display: block;
            }
            .ggui-file-count {
                font-size: 13px;
                margin-bottom: 24px;
                color: #6b7280;
                font-family: Consolas, Menlo, Monaco, monospace;
            }
            .ggui-file-count span {
                color: #4f46e5;
                font-weight: 700;
            }
            .ggui-steps {
                margin-bottom: 24px;
            }
            .ggui-step {
                padding: 6px 0;
                font-size: 13px;
                color: #4b5563;
                display: flex;
                align-items: center;
                gap: 8px;
            }
            .ggui-step.active {
                color: #d4d4d4;
            }
            .ggui-step.done {
                color: #10b981;
            }
            .ggui-progress-bar {
                height: 2px;
                background: rgba(255,255,255,0.06);
                margin: 4px 0 8px 0;
                border-radius: 2px;
                overflow: hidden;
            }
            .ggui-progress-bar .bar {
                height: 100%;
                background: linear-gradient(90deg, #4f46e5, #7c3aed);
                width: 0.001%;
                transition: width 0.3s ease;
            }
            .progress-text {
                color: #4f46e5;
                font-size: 11px;
                font-family: Consolas, Menlo, Monaco, monospace;
            }
            .ggui-buttons {
                display: flex;
                gap: 10px;
            }
            .ggui-btn {
                flex: 1;
                padding: 10px 20px;
                border: none;
                border-radius: 8px;
                font-family: 'Sofia Sans', sans-serif;
                font-size: 13px;
                font-weight: 600;
                cursor: pointer;
                transition: background 0.15s;
            }
            .ggui-btn-close {
                background: rgba(255,255,255,0.06);
                color: #9ca3af;
                border: 1px solid rgba(255,255,255,0.08);
            }
            .ggui-btn-close:hover {
                background: rgba(255,255,255,0.1);
                color: #d4d4d4;
            }
            .ggui-btn-open {
                background: #4f46e5;
                color: #ffffff;
            }
            .ggui-btn-open:hover {
                background: #4338ca;
            }
        </style>
    </head>
    <body>
    <div class="ggui-container">
        <div class="ggui-logo">
            <?= LOGO_SVG; ?>
        </div>

        <div class="ggui-file-count">
            Found <span id="fileCount">0</span> PHP files
        </div>

        <div class="ggui-steps" id="stepsContainer">
            <!-- Steps will be added dynamically -->
        </div>

        <div class="ggui-buttons" id="buttonContainer" style="display: none;">
            <button class="ggui-btn ggui-btn-close" onclick="closeWindow()">Close window</button>
            <button class="ggui-btn ggui-btn-open" onclick="openDocumentation()">Open documentation</button>
        </div>
    </div>

    <script>
        /* ========= GGUI-ONLY JAVASCRIPT ========= */
        let GGUI_TOTAL_FILES = 0;
        let generationStarted = false;

        const STEP_LABELS = {
            'scan': 'Scanning directories',
            'parsing': 'Analyzing PHP files',
            'tree': 'Building tree structure',
            'structure': 'Creating directory structure',
            'html': 'Generating HTML files',
            'dir-index': 'Generating directory indexes',
            'main-index': 'Generating main index.html',
            'htaccess': 'Creating .htaccess',
            'json-index': 'Generating JSON file index'
        };

        let currentStepKey = null;
        let currentStepEl = null;
        let currentProgressBar = null;
        let currentProgressText = null;

        function initGgui() {
            fetch('?action=get_file_count')
                .then(response => response.json())
                .then(data => {
                    GGUI_TOTAL_FILES = data.count;
                    animateGguiFileCount();
                    if (!generationStarted) {
                        generationStarted = true;
                        startSSEGeneration();
                    }
                })
                .catch(err => {
                    console.error('Error getting file count:', err);
                    GGUI_TOTAL_FILES = 0;
                    if (!generationStarted) {
                        generationStarted = true;
                        startSSEGeneration();
                    }
                });
        }

        function animateGguiFileCount() {
            let count = 0;
            const increment = Math.max(1, Math.ceil(GGUI_TOTAL_FILES / 30));
            const interval = setInterval(() => {
                count += increment;
                if (count >= GGUI_TOTAL_FILES) {
                    count = GGUI_TOTAL_FILES;
                    clearInterval(interval);
                }
                const countEl = document.getElementById('fileCount');
                if (countEl) countEl.textContent = count;
            }, 30);
        }

        function closeCurrentStep() {
            if (!currentStepEl) return;
            currentStepEl.classList.remove('active');
            currentStepEl.classList.add('done');
            if (currentProgressText) {
                currentProgressText.textContent = 'Done!';
                currentProgressText.style.color = '#ffffff';
            }
            if (currentProgressBar) currentProgressBar.style.display = 'none';
            currentStepEl = null;
            currentProgressBar = null;
            currentProgressText = null;
        }

        function openStep(key, label) {
            const container = document.getElementById('stepsContainer');
            if (!container) return;

            currentStepKey = key;
            currentStepEl = document.createElement('div');
            currentStepEl.className = 'ggui-step active';
            currentStepEl.innerHTML = label + ' - <span class="progress-text">0%</span>';
            container.appendChild(currentStepEl);

            currentProgressBar = document.createElement('div');
            currentProgressBar.className = 'ggui-progress-bar';
            currentProgressBar.innerHTML = '<div class="bar"></div>';
            container.appendChild(currentProgressBar);

            currentProgressText = currentStepEl.querySelector('.progress-text');
        }

        function updateStep(pct) {
            if (!currentStepEl || !currentProgressBar || !currentProgressText) return;
            const bar = currentProgressBar.querySelector('.bar');
            bar.style.width = pct + '%';
            currentProgressText.textContent = pct + '%';
        }

        function startSSEGeneration() {
            const es = new EventSource(window.location.pathname + '?generate=1');

            es.addEventListener('progress', (e) => {
                let data;
                try { data = JSON.parse(e.data); } catch (err) { return; }
                const label = STEP_LABELS[data.step] || data.step;

                if (currentStepKey !== data.step) {
                    closeCurrentStep();
                    openStep(data.step, label);
                }
                updateStep(data.pct);
            });

            es.addEventListener('done', () => {
                closeCurrentStep();
                es.close();
                showGguiCompletion();
            });

            es.addEventListener('error', (e) => {
                console.error('SSE connection error', e);
                // EventSource auto-reconnects by default; close to prevent loops when done
                if (es.readyState === EventSource.CLOSED) return;
            });
        }

        // Show completion buttons
        function showGguiCompletion() {
            const buttonContainer = document.getElementById('buttonContainer');
            if (buttonContainer) {
                buttonContainer.style.display = 'flex';

                // Auto-redirect after 2 seconds
                setTimeout(() => {
                    openDocumentation();
                }, 20000000);
            }
        }

        // Close window
        function closeWindow() {
            window.close();
            setTimeout(() => {
                if (!window.closed) {
                    window.location.href = 'about:blank';
                }
            }, 100);
        }

        // Open documentation (WITHOUT language parameter)
        function openDocumentation() {
            // Always use clean URL without parameters
            const docUrl = '<?= $settings['output_dir']; ?>/index.html';

            if (window.opener) {
                window.opener.location.href = docUrl;
                window.close();
            } else {
                window.location.href = docUrl;
            }
        }

        // Start when DOM is ready
        if (document.readyState === 'loading') {
            document.addEventListener('DOMContentLoaded', initGgui);
        } else {
            initGgui();
        }
    </script>
    </body>
    </html>
    <?php
    exit;
}