commit 6edebcd5b1363536c74f6e1c6f268adb7029daa0 Author: Yuri Date: Thu Nov 13 00:58:17 2025 +0100 initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..9f6cc98 --- /dev/null +++ b/README.md @@ -0,0 +1,65 @@ +# WHMCS VPS Management Module - ArkHost VPSAG + +A WHMCS server module for VPS management with multi-language support. + +## Features + +- VPS control (start/stop/restart) +- Backup management +- Firewall configuration +- OS reinstallation with advanced options +- Resource monitoring +- VNC console access +- 8 language support +- Responsive design + +## Requirements + +- WHMCS 8.9+ +- PHP 7.4+ + + +## Changelog + +### Version 1.4 +- Fixed firewall rule duplication bug when adding new rules +- Added validation warning for ANY protocol with specific port numbers +- Redesigned firewall interface with modern card-based layout +- Created standalone Firewall tab for better organization +- Completely redesigned VPS Overview section with: + - Server Status Card (hostname, IPs, OS, status, uptime, server type) + - Resource Allocation Card (CPU cores, Memory, Storage, Traffic) + - Resource Usage Card (RAM, Bandwidth, CPU) + - Quick Actions Card (Start/Stop, Restart, VNC Console) +- Fixed Quick Actions button functionality +- Completed all language translations (8 languages: English, Dutch, French, German, Italian, Portuguese, Russian, Spanish) +- Enhanced UI styling with gradient backgrounds and smooth animations +- Improved responsive design and layout consistency +- Removed duplicate VPS Information section +- Optimized resource display (removed redundant disk space usage) + +### Version 1.3 +- Enhanced API integration +- Performance improvements +- Bug fixes + +### Version 1.2 +- Custom notifications replace browser popups +- Confirmation dialogs for critical actions +- Multi-language support for all notifications +- Smart post-installation script examples based on OS +- Fixed firewall rules not displaying after creation +- Improved UI styling and animations + +### Version 1.1 +- Basic VPS management +- Backup operations +- Firewall rules +- OS reinstall + +### Version 1.0 +- Initial release + + +MIT License +© 2025 ArkHost diff --git a/modules/servers/ArkhostVPSAG/ArkhostVPSAG.php b/modules/servers/ArkhostVPSAG/ArkhostVPSAG.php new file mode 100644 index 0000000..2d424ca --- /dev/null +++ b/modules/servers/ArkhostVPSAG/ArkhostVPSAG.php @@ -0,0 +1,991 @@ + + * @link https://arkhost.com + */ + +if (!defined('WHMCS')) { + http_response_code(403); + exit('Access denied'); +} + +use WHMCS\Config\Setting; +use WHMCS\Database\Capsule; + +function ArkhostVPSAG_GetVPSID(array $params) { + $vpsId = $params['model']->serviceProperties->get('vpsag'); + // Handle both VPSAG-xxx and VPS-xxx formats, return just the numeric ID + return str_replace(['VPSAG-', 'VPS-'], '', $vpsId); +} + +function ArkhostVPSAG_API(array $params) { + $url = 'https://www.vpsag.com/api/v1/'; + $data = []; + $method = ''; + + switch ($params['action']) { + case 'Packages': + $url .= 'plans'; + $method .= 'GET'; + break; + + case 'Operating Systems': + $url .= 'os/plan/' . $params['plan_id']; + $method .= 'GET'; + break; + + case 'Upgrades': + $url .= 'upgrade/plans'; + $method .= 'GET'; + break; + + case 'Discount': + $url .= 'discount'; + $method .= 'GET'; + break; + + case 'Balance': + $url .= 'balance'; + $method .= 'GET'; + break; + + case 'Order': + $planId = ArkhostVPSAG_GetOption($params, 'planid'); + $url .= 'order/' . $planId; + $method .= 'POST'; + + $billingCycles = array( + 'Monthly' => 1, + 'Quarterly' => 3, + 'Semi-Annually' => 6, + 'Annually' => 12, + 'Biennially' => 24, + 'Triennially' => 36 + ); + + $data += array( + 'hostname' => $params['domain'] ?? 'vps.example.com', + 'notify_url' => Setting::getValue('SystemURL') . '/modules/servers/ArkhostVPSAG/callback.php', + 'os' => ArkhostVPSAG_GetOption($params, 'osid'), + 'billing_term' => $billingCycles[$params['model']['billingcycle']] ?? 1, + ); + break; + + case 'Server Info': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params); + $method .= 'GET'; + break; + + case 'Label': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/label'; + $method .= 'POST'; + + $data += array( + 'val' => $params['label'], + ); + break; + + case 'Graphs': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/graph/' . $params['time']; + $method .= 'GET'; + break; + + case 'Operating Systems - Server': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/os'; + $method .= 'GET'; + break; + + case 'Cancel': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/cancel'; + $method .= 'POST'; + + $data += array( + 'when' => $params['when'], + ); + break; + + case 'Stop Cancellation': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/stop-cancellation'; + $method .= 'POST'; + break; + + case 'VNC Console': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/vnc'; + $method .= 'GET'; + break; + + case 'Reinstall': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/reinstall'; + $method .= 'POST'; + + $data += array( + 'os' => $params['os'], + 'notify_url' => Setting::getValue('SystemURL') . '/modules/servers/ArkhostVPSAG/callback.php', + ); + + // Add optional SSH key if provided + if (!empty($params['ssh_key'])) { + $data['ssh_key'] = $params['ssh_key']; + } + + // Add optional post-install script if provided + if (!empty($params['run_on_install'])) { + $data['run_on_install'] = base64_encode($params['run_on_install']); + } + + // Set SSH password policy (1 = disable, 2 = enable) + $data['no_ssh_password'] = isset($params['no_ssh_password']) && $params['no_ssh_password'] ? 1 : 2; + break; + + case 'Reboot': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/action/reboot'; + $method .= 'POST'; + break; + + case 'Stop': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/action/stop'; + $method .= 'POST'; + break; + + case 'Shutdown': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/action/shutdown'; + $method .= 'POST'; + break; + + case 'Start': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/action/start'; + $method .= 'POST'; + break; + + case 'Disable': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/action/disable'; + $method .= 'POST'; + break; + + case 'Enable': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/action/enable'; + $method .= 'POST'; + break; + + case 'IPv4 Addresses': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/ipv4'; + $method .= 'GET'; + break; + + case 'Reverse DNS': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/rdns/' . $params['ip']; + $method .= 'POST'; + + $data += array( + 'rdns' => $params['rdns'] + ); + break; + + case 'Addons': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/addons'; + $method .= 'GET'; + break; + + case 'Upgrade': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/upgrade/plan'; + $method .= 'POST'; + + $data += array( + 'plan_id' => ArkhostVPSAG_GetOption($params, 'planid'), + ); + break; + + case 'Hostname rDNS': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/hostname'; + $method .= 'POST'; + + $data += array( + 'hostname' => $params['hostname'] + ); + break; + + case 'Create backup': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/backup'; + $method .= 'POST'; + break; + + case 'Delete backup': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/backup/' . $params['file']; + $method .= 'DELETE'; + break; + + case 'List backups': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/backup'; + $method .= 'GET'; + break; + + case 'Restore backup': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/restore/' . $params['file']; + $method .= 'POST'; + break; + + case 'Get Firewall rules': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/firewall'; + $method .= 'GET'; + break; + + case 'Add Firewall rules': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/firewall'; + $method .= 'POST'; + + $data += array( + 'action' => $params['firewallAction'], + 'protocol' => $params['protocol'], + 'source' => $params['source'], + 'port' => $params['port'], + 'note' => $params['note'], + ); + break; + + case 'Delete Firewall rule': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/firewall/' . $params['rule_id']; + $method .= 'DELETE'; + break; + + case 'Commit Firewall rules': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/firewall/resync'; + $method .= 'POST'; + break; + + case 'ISO Images': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/iso'; + $method .= 'GET'; + break; + + case 'Load ISO': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/iso/' . $params['iso_id']; + $method .= 'POST'; + break; + + case 'Eject ISO': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/iso/0'; + $method .= 'POST'; + break; + + case 'Reset root': + $url .= 'vps/' . ArkhostVPSAG_GetVPSID($params) . '/reset-root'; + $method .= 'POST'; + break; + + default: + throw new Exception('Invalid action: ' . $params['action']); + break; + } + + $curl = curl_init(); + curl_setopt($curl, CURLOPT_URL, $url); + curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method); + curl_setopt($curl, CURLOPT_TIMEOUT, 15); + curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); + curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); + curl_setopt($curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_301); + curl_setopt($curl, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1_2); + curl_setopt($curl, CURLOPT_USERAGENT, 'ArkHost - VPSAG WHMCS'); + curl_setopt($curl, CURLOPT_HTTPHEADER, array('X_API_USER: ' . $params['serverusername'], 'X_API_KEY: ' . $params['serverpassword'])); + + if ($method === 'POST' || $method === 'PATCH') { + curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data)); + } + + $responseData = curl_exec($curl); + $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); + + $responseData = json_decode($responseData, true); + + if ($statusCode === 0) throw new Exception('cURL Error: ' . curl_error($curl)); + + curl_close($curl); + + logModuleCall( + 'ArkHost - VPSAG', + $url, + !empty($data) ? json_encode($data) : '', + print_r($responseData, true) + ); + + if (isset($responseData['status']) && $responseData['status'] === 0) throw new Exception($responseData['result']); + + return $responseData['result']; +} + +function ArkhostVPSAG_Error($func, $params, Exception $err) { + logModuleCall('ArkHost - VPSAG', $func, $params, $err->getMessage(), $err->getTraceAsString()); +} + +function ArkhostVPSAG_MetaData() { + return array( + 'DisplayName' => 'ArkHost - VPSAG', + 'APIVersion' => '1.1', + 'RequiresServer' => true, + ); +} + +function ArkhostVPSAG_ConfigOptions() { + $error = array( + 'error' => array( + 'FriendlyName' => 'Error', + 'Description' => 'Please double check if you selected a Server Group and/or your details are correct.', + 'Type' => '', + ), + ); + + $array = array( + 'planid' => array( + 'FriendlyName' => 'Plan', + 'Description' => 'The Plan desired (Configurable option: planid).', + 'Type' => 'dropdown', + 'Options' => array(), + ), + 'osid' => array( + 'FriendlyName' => 'Operating System', + 'Description' => 'The Operating System desired (Configurable option: osid).', + 'Type' => 'dropdown', + 'Options' => array(), + ), + // Extra resource options removed - now handled via plan selection + // Plans have fixed resources defined within them in the new API + ); + + try { + if (basename($_SERVER['SCRIPT_NAME'], '.php') === 'configproducts' && ($_REQUEST['action'] === 'module-settings' || $_POST['action'] === 'module-settings')) { + $id = 0; + $product; + $serverGroup = 0; + + if ($_SERVER['REQUEST_METHOD'] === 'POST') { + $id = (int) $_POST['id']; + + $product = Capsule::table('tblproducts')->where('id', $id)->first(); + $serverGroup = (int) $_POST['servergroup']; + } else { + $id = (int) $_REQUEST['id']; + + $product = Capsule::table('tblproducts')->where('id', $id)->first(); + $serverGroup = (int) $product->servergroup; + } + + // Only proceed if a server group is actually selected + if ($serverGroup == 0) { + return $array; // Return basic array structure when no server group selected + } + + $serverGroup = Capsule::table('tblservergroupsrel')->where('groupid', $serverGroup)->first(); + if (!$serverGroup) { + // Return basic array if server group not found, don't throw exception + return $array; + } + + $server = Capsule::table('tblservers')->where('id', $serverGroup->serverid)->first(); + if (!$server) { + // Return basic array if server not found, don't throw exception + return $array; + } + + $params = array( + 'serverusername' => $server->username, + 'serverpassword' => decrypt($server->password), + ); + + $params['action'] = 'Packages'; + $packageslist = ArkhostVPSAG_API($params); + + foreach ($packageslist as $package) { + $array['planid']['Options'] += array( + $package['id'] => $package['name'] . ' (' . $package['price'] . '€)' + ); + } + + if ($product->configoption1 == '') return $array; + + $params['action'] = 'Operating Systems'; + $params['plan_id'] = $product->configoption1; + $operatingSystems = ArkhostVPSAG_API($params); + + foreach ($operatingSystems as $operatingSystem) { + $array['osid']['Options'] += array( + $operatingSystem['id'] => $operatingSystem['name'] + ); + } + + // Note: Extra resource upgrades are now handled via plan selection in the new API + // Plans have fixed resources defined within them, no individual resource pricing + } + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + + $error['error']['Description'] = 'Received the error: ' . $err->getMessage() . ' Check module debug log for more detailed error.'; + return $error; + } + + return $array; +} + +function ArkhostVPSAG_GetOption(array $params, $id, $default = NULL) { + $options = ArkhostVPSAG_ConfigOptions(); + + $friendlyName = $options[$id]['FriendlyName']; + + if (isset($params['configoptions'][$friendlyName]) && $params['configoptions'][$friendlyName] !== '') { + return $params['configoptions'][$friendlyName]; + } else if (isset($params['configoptions'][$id]) && $params['configoptions'][$id] !== '') { + return $params['configoptions'][$id]; + } else if (isset($params['customfields'][$friendlyName]) && $params['customfields'][$friendlyName] !== '') { + return $params['customfields'][$friendlyName]; + } else if (isset($params['customfields'][$id]) && $params['customfields'][$id] !== '') { + return $params['customfields'][$id]; + } + + $found = false; + $i = 0; + + foreach ($options as $key => $value) { + $i++; + if ($key === $id) { + $found = true; + break; + } + } + + if ($found && isset($params['configoption' . $i]) && $params['configoption' . $i] !== '') { + return $params['configoption' . $i]; + } + + return $default; +} + +function ArkhostVPSAG_TestConnection(array $params) { + $err = ''; + + try { + $params['action'] = 'Balance'; + ArkhostVPSAG_API($params); + } catch (Exception $e) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $e); + $err = 'Received the error: ' . $e->getMessage() . ' Check module debug log for more detailed error.'; + } + + return [ + 'success' => $err === '', + 'error' => $err, + ]; +} + +function ArkhostVPSAG_CreateAccount(array $params) { + try { + $params['action'] = 'Order'; + $create = ArkhostVPSAG_API($params); + + // Validate API response - the API function already handles status=0 errors + // but we need to ensure we have a valid vps_id + if (!is_array($create) || !isset($create['vps_id']) || empty($create['vps_id'])) { + if (is_array($create)) { + logActivity('VPSAG Order Failed - Invalid Response: ' . json_encode($create)); + } else { + logActivity('VPSAG Order Failed - Non-array response: ' . gettype($create)); + } + throw new Exception('Invalid response from API'); + } + + // Ensure vps_id is numeric and valid + if (!is_numeric($create['vps_id']) || $create['vps_id'] <= 0) { + throw new Exception('Invalid response from API'); + } + + $params['model']->serviceProperties->save([ + 'vpsag|VPSAG ID' => 'VPSAG-' . $create['vps_id'], + ]); + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + return 'Received the error: ' . $err->getMessage() . ' Check module debug log for more detailed error.'; + } + + return 'success'; +} + +function ArkhostVPSAG_SuspendAccount(array $params) { + try { + $params['action'] = 'Disable'; + ArkhostVPSAG_API($params); + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + return 'Received the error: ' . $err->getMessage() . ' Check module debug log for more detailed error.'; + } + + return 'success'; +} + +function ArkhostVPSAG_UnsuspendAccount(array $params) { + try { + $params['action'] = 'Enable'; + ArkhostVPSAG_API($params); + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + return 'Received the error: ' . $err->getMessage() . ' Check module debug log for more detailed error.'; + } + + return 'success'; +} + +function ArkhostVPSAG_TerminateAccount(array $params) { + try { + $params['action'] = 'Cancel'; + $params['when'] = 'now'; + ArkhostVPSAG_API($params); + + Capsule::table('tblhosting')->where('id', $params['serviceid'])->update(array( + 'username' => '', + 'password' => '', + )); + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + return 'Received the error: ' . $err->getMessage() . ' Check module debug log for more detailed error.'; + } + + return 'success'; +} + + + +function ArkhostVPSAG_ChangePackage(array $params) { + try { + $params['action'] = 'Upgrade'; + ArkhostVPSAG_API($params); + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + return 'Received the error: ' . $err->getMessage() . ' Check module debug log for more detailed error.'; + } + + return 'success'; +} + +function ArkhostVPSAG_Start(array $params) { + try { + ArkhostVPSAG_API($params); + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + return 'Received the error: ' . $err->getMessage() . ' Check module debug log for more detailed error.'; + } + + return 'success'; +} + +function ArkhostVPSAG_Reboot(array $params) { + try { + ArkhostVPSAG_API($params); + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + return 'Received the error: ' . $err->getMessage() . ' Check module debug log for more detailed error.'; + } + + return 'success'; +} + +function ArkhostVPSAG_Stop(array $params) { + try { + ArkhostVPSAG_API($params); + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + return 'Received the error: ' . $err->getMessage() . ' Check module debug log for more detailed error.'; + } + + return 'success'; +} + +function ArkhostVPSAG_VNC(array $params) { + try { + $params['action'] = 'VNC Console'; + $vnc = ArkhostVPSAG_API($params); + + echo ''; + // header('Location: ' . $vnc['vnc_url']); + WHMCS\Terminus::getInstance()->doExit(); + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + + return array( + 'templatefile' => 'template/error', + 'templateVariables' => array( + 'error' => $err->getMessage(), + ), + ); + } +} + +function ArkhostVPSAG_AdminCustomButtonArray() { + return array( + 'Start' => 'Start', + 'Stop'=> 'Stop', + 'Reboot' => 'Reboot', + 'VNC Console'=> 'VNC', + ); +} + +function ArkhostVPSAG_AdminLink(array $params) { + try { + $params['action'] = 'Balance'; + $balance = ArkhostVPSAG_API($params); + + $params['action'] = 'Discount'; + $discount = ArkhostVPSAG_API($params); + + return ' Balance: ' . $balance['balance'] . '€
Discount: ' . $discount['percent'] . '%'; + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + return 'Received the error: ' . $err->getMessage() . ' Check module debug log for more detailed error.'; + } +} + +function ArkhostVPSAG_ClientAreaAPI(array $params) { + try { + $action = App::getFromRequest('api'); + $actions = array('Server Info', 'Graphs', 'Reinstall', 'Reboot', 'Stop', 'Start', 'IPv4 Addresses', 'Hostname rDNS', 'Create backup', 'Delete backup', 'List backups', 'Restore backup', 'Get Firewall rules', 'Add Firewall rules', 'Delete Firewall rule', 'Commit Firewall rules', 'ISO Images', 'Load ISO', 'Eject ISO', 'Reset root'); + $results = array('result' => 'success'); + + if (in_array($action, $actions)) { + foreach ($_POST as $key => $value) { + $params[$key] = $value; + } + + $params['action'] = $action; + $result = ArkhostVPSAG_API($params); + + // Special handling for specific responses + if ($action === 'Graphs') { + // If result contains graphs data, format it properly + if (isset($result['graphs'])) { + $results['graphs'] = $result['graphs']; + } else if (isset($result['cpu_img']) || isset($result['mem_img']) || isset($result['net_img']) || isset($result['disk_img'])) { + // If the response has individual graph fields, group them + $results['graphs'] = array( + 'cpu_img' => isset($result['cpu_img']) ? $result['cpu_img'] : null, + 'mem_img' => isset($result['mem_img']) ? $result['mem_img'] : null, + 'net_img' => isset($result['net_img']) ? $result['net_img'] : null, + 'disk_img' => isset($result['disk_img']) ? $result['disk_img'] : null + ); + } else { + // If no graph data found, set empty graphs + $results['graphs'] = array( + 'cpu_img' => null, + 'mem_img' => null, + 'net_img' => null, + 'disk_img' => null + ); + } + } else if ($action === 'List backups') { + // Handle backup list response - VPSAG returns array directly + // Pass the result directly - let JavaScript handle the parsing + $results = $result; + } else { + $results = array_merge($results, is_array($result) ? $result : array('data' => $result)); + } + + return array('jsonResponse' => $results); + } else { + throw new Exception('Action not allowed'); + } + } catch (Exception $e) { + return array('jsonResponse' => array('result' => 'error', 'message' => $e->getMessage())); + } +} + +function ArkhostVPSAG_DeliverFile(array $params) { + try { + $dir = __DIR__ . '/template/'; + $file = App::getFromRequest('file'); + $files = array('app.min.css', 'app.min.js'); + + if (in_array($file, $files)) { + $type = ''; + + if (function_exists('ob_gzhandler')) { + ob_start('ob_gzhandler'); + } + + if (strpos($file, '.js') !== false) { + $dir .= 'js/'; + $type = 'application/javascript'; + } else if (strpos($file, '.css') !== false) { + $dir .= 'css/'; + $type = 'text/css'; + } else { + $type = 'text/html'; + } + + header('Content-Type: ' . $type . '; charset=utf-8'); + header('Cache-Control: max-age=604800, public'); + + echo file_get_contents($dir . $file); + WHMCS\Terminus::getInstance()->doExit(); + } else { + throw new Exception('File not found'); + } + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + return array('jsonResponse' => array('result' => 'error', 'message' => $err->getMessage())); + } +} + + + +function ArkhostVPSAG_ClientAreaCustomButtonArray() { + $_LANG = ArkhostVPSAG_Translation(); + + return array( + $_LANG['Start'] => 'Start', + $_LANG['Stop'] => 'Stop', + $_LANG['Restart'] => 'Reboot', + $_LANG['VNC'] => 'VNC', + ); +} + +function ArkhostVPSAG_ClientAreaAllowedFunctions() { + return array('ClientAreaAPI', 'DeliverFile'); +} + +function ArkhostVPSAG_ClientArea(array $params) { + if ($params['moduletype'] !== 'ArkhostVPSAG') return; + + try { + // Check if VPS ID is available + $vpsId = $params['model']->serviceProperties->get('vpsag'); + if (empty($vpsId)) { + throw new Exception('Service not properly provisioned'); + } + + // Get clean VPS ID + $cleanVpsId = ArkhostVPSAG_GetVPSID($params); + if (empty($cleanVpsId)) { + throw new Exception('Invalid VPS ID format'); + } + + // Get server info and operating systems data + $params['action'] = 'Server Info'; + $serverInfo = ArkhostVPSAG_API($params); + + // Check if server info is valid + if (!is_array($serverInfo) || empty($serverInfo)) { + throw new Exception('Unable to retrieve server information from API'); + } + + $params['action'] = 'Operating Systems - Server'; + $operatingSystemsTemp = ArkhostVPSAG_API($params); + + // Check if operating systems data is valid + if (!is_array($operatingSystemsTemp)) { + $operatingSystemsTemp = array(); + } + + $dirImages = __DIR__ . '/template/img/'; + $availableImages = glob($dirImages . '*.png'); + $images = array(); + + foreach ($availableImages as $key => $image) { + $images[explode('.png', explode($dirImages, $image)[1])[0]] = 'data:image/png;base64,' . base64_encode(file_get_contents($image)); + } + + $dirOS = __DIR__ . '/template/img/os/'; + $availableOS = glob($dirOS . '*.png'); + $operatingSystems = array(); + + foreach ($availableOS as $key => $os) { + $availableOS[$key] = explode('.png', explode($dirOS, $os)[1])[0]; + } + + // Only process operating systems if we have valid data + if (!empty($operatingSystemsTemp)) { + foreach ($operatingSystemsTemp as $key => $operatingSystem) { + // Create separate groups for different Linux distributions + $osName = strtolower($operatingSystem['name']); + + // Determine the proper group based on OS name + if (strpos($osName, 'almalinux') !== false || strpos($osName, 'alma') !== false) { + $group = 'almalinux'; + $groupName = 'AlmaLinux'; + } elseif (strpos($osName, 'rocky') !== false || strpos($osName, 'rockylinux') !== false) { + $group = 'rocky'; + $groupName = 'Rocky Linux'; + } elseif (strpos($osName, 'centos') !== false) { + $group = 'centos'; + $groupName = 'CentOS'; + } elseif (strpos($osName, 'debian') !== false) { + $group = 'debian'; + $groupName = 'Debian'; + } elseif (strpos($osName, 'ubuntu') !== false) { + $group = 'ubuntu'; + $groupName = 'Ubuntu'; + } elseif (strpos($osName, 'windows') !== false) { + $group = 'windows'; + $groupName = 'Windows'; + } else { + // Fallback to original group + $group = $operatingSystem['group']; + $groupName = $operatingSystem['group_name']; + } + + if (!isset($operatingSystems[$group])) { + // Map group names to correct image filenames + $imageFile = $group; + if ($group === 'rocky') { + $imageFile = 'rockylinux'; + } + + $image = file_get_contents($dirOS . (in_array($imageFile, $availableOS) ? $imageFile : 'others') . '.png'); + + $operatingSystems[$group] = array( + 'name' => $groupName, + 'image' => 'data:image/png;base64,' . base64_encode($image), + 'versions' => array(), + ); + } + + $operatingSystems[$group]['versions'][] = $operatingSystem; + } + + // Process operating system info only if we have data + if (isset($serverInfo['os']) && !empty($operatingSystemsTemp)) { + $osId = $serverInfo['os']; + $osIndex = array_search($osId, array_column($operatingSystemsTemp, 'id')); + + if ($osIndex !== false && isset($operatingSystemsTemp[$osIndex])) { + $currentOS = $operatingSystemsTemp[$osIndex]; + $osName = strtolower($currentOS['name']); + + // Determine the proper group based on current OS name + if (strpos($osName, 'almalinux') !== false || strpos($osName, 'alma') !== false) { + $group = 'almalinux'; + } elseif (strpos($osName, 'rocky') !== false || strpos($osName, 'rockylinux') !== false) { + $group = 'rocky'; + } elseif (strpos($osName, 'centos') !== false) { + $group = 'centos'; + } elseif (strpos($osName, 'debian') !== false) { + $group = 'debian'; + } elseif (strpos($osName, 'ubuntu') !== false) { + $group = 'ubuntu'; + } elseif (strpos($osName, 'windows') !== false) { + $group = 'windows'; + } else { + $group = $currentOS['group']; + } + + // Use the specific OS information instead of the generic group + $serverInfo['operatingSystem'] = array( + 'name' => $currentOS['name'], + 'image' => isset($operatingSystems[$group]) ? $operatingSystems[$group]['image'] : 'data:image/png;base64,' . base64_encode(file_get_contents(__DIR__ . '/template/img/os/others.png')) + ); + } else { + // Fallback if OS not found in list + $serverInfo['operatingSystem'] = array( + 'name' => 'OS ID: ' . $osId, + 'image' => 'data:image/png;base64,' . base64_encode(file_get_contents(__DIR__ . '/template/img/os/others.png')) + ); + } + } + } + + // Set default OS info if not available + if (!isset($serverInfo['operatingSystem']) || !is_array($serverInfo['operatingSystem'])) { + $serverInfo['operatingSystem'] = array( + 'name' => 'Unknown OS', + 'image' => 'data:image/png;base64,' . base64_encode(file_get_contents($dirOS . 'others.png')) + ); + } + + $serverInfo['status'] = isset($serverInfo['status']) ? ($serverInfo['status'] !== 'ok' ? $serverInfo['status'] : (isset($serverInfo['vm_status']) ? $serverInfo['vm_status'] : 'unknown')) : 'unknown'; + $serverInfo['statusImage'] = isset($images[$serverInfo['status']]) ? $images[$serverInfo['status']] : (isset($images['unknown']) ? $images['unknown'] : ''); + $serverInfo['statusDescription'] = ucfirst($serverInfo['status']); + + // Set default values for missing data + $serverInfo['hostname'] = isset($serverInfo['hostname']) ? $serverInfo['hostname'] : 'N/A'; + $serverInfo['ip'] = isset($serverInfo['ip']) ? $serverInfo['ip'] : 'N/A'; + $serverInfo['uptime_text'] = isset($serverInfo['uptime_text']) ? $serverInfo['uptime_text'] : 'N/A'; + $serverInfo['server_type'] = isset($serverInfo['category']) ? $serverInfo['category'] : 'Standard'; + $serverInfo['cpu_usage'] = isset($serverInfo['cpu_usage']) ? $serverInfo['cpu_usage'] : 0; + $serverInfo['ram_usage'] = isset($serverInfo['ram_usage']) ? $serverInfo['ram_usage'] : 0; + $serverInfo['ram'] = isset($serverInfo['ram']) ? $serverInfo['ram'] : 1; + + // Handle disk usage data (API may not always return this field) + + $serverInfo['disk_used'] = isset($serverInfo['disk_usage']) ? $serverInfo['disk_usage'] : + (isset($serverInfo['disk_used']) ? $serverInfo['disk_used'] : 0); + $serverInfo['disk'] = isset($serverInfo['disk']) ? $serverInfo['disk'] : 1; + $serverInfo['bandwidth_used'] = isset($serverInfo['bandwidth_used']) ? $serverInfo['bandwidth_used'] : 0; + $serverInfo['bandwidth'] = isset($serverInfo['bandwidth']) ? $serverInfo['bandwidth'] : 1; + + return array( + 'templatefile' => 'template/clientarea_direct', + 'templateVariables' => array( + 'images' => $images, + 'serverInfo' => $serverInfo, + 'operatingSystems' => $operatingSystems, + 'token' => generate_token('plain'), + '_LANG' => ArkhostVPSAG_Translation(), + ) + ); + } catch (Exception $err) { + ArkhostVPSAG_Error(__FUNCTION__, $params, $err); + + return array( + 'templatefile' => 'template/error', + 'templateVariables' => array( + 'error' => $err->getMessage(), + 'image' => 'data:image/png;base64,' . base64_encode(file_get_contents(__DIR__ . '/template/img/notice.png')) + ) + ); + } +} + +function ArkhostVPSAG_Translation() { + $lang = Setting::getValue('Language'); + $language = Lang::getName(); + $_ADDONLANG = []; + + if ($language === '') { + $language = $lang; + } + + if ($language) { + $addonLangFile = ROOTDIR . '/modules/servers/ArkhostVPSAG/lang/' . $language . '.php'; + + if (file_exists($addonLangFile)) { + swapLang($language); + + ob_start(); + require $addonLangFile; + ob_end_clean(); + } + } + + if (count($_ADDONLANG) === 0) { + $addonLangFile = ROOTDIR . '/modules/servers/ArkhostVPSAG/lang/' . $lang . '.php'; + + if (file_exists($addonLangFile)) { + swapLang($lang); + + ob_start(); + require $addonLangFile; + ob_end_clean(); + } + } + + if (count($_ADDONLANG) === 0) { + $addonLangFile = ROOTDIR . '/modules/servers/ArkhostVPSAG/lang/english.php'; + + if (file_exists($addonLangFile)) { + ob_start(); + require $addonLangFile; + ob_end_clean(); + } + } + + return $_ADDONLANG; +} diff --git a/modules/servers/ArkhostVPSAG/callback.php b/modules/servers/ArkhostVPSAG/callback.php new file mode 100644 index 0000000..8e11dba --- /dev/null +++ b/modules/servers/ArkhostVPSAG/callback.php @@ -0,0 +1,93 @@ + + */ + +if (empty($_POST)) { + http_response_code(400); + exit('Bad Request'); +} + +require_once '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'init.php'; +require_once ROOTDIR . DIRECTORY_SEPARATOR . 'modules' . DIRECTORY_SEPARATOR . 'servers' . DIRECTORY_SEPARATOR . 'ArkhostVPSAG' . DIRECTORY_SEPARATOR . 'ArkhostVPSAG.php'; + +use WHMCS\Database\Capsule; + +$_POST = array_map('html_entity_decode', $_POST); + +// Look for the service by VPSAG ID in service properties +$serviceProperty = Capsule::table('tblservice_properties') + ->where('property', 'vpsag|VPSAG ID') + ->where('value', 'VPSAG-' . $_POST['server_id']) + ->first(); + +if (!$serviceProperty) { + // Fallback: try to find in custom fields for backward compatibility + $customField = Capsule::table('tblcustomfieldsvalues')->where('value', 'VPSAG-' . $_POST['server_id'])->first(); + if ($customField) { + $service = WHMCS\Service\Service::find($customField->relid); + } else { + http_response_code(404); + exit('Service not found'); + } +} else { + $service = WHMCS\Service\Service::find($serviceProperty->service_id); +} + +if (!$service) { + http_response_code(404); + exit('Service not found'); +} + +$server = Capsule::table('tblservers')->where('id', $service->server)->first(); + +$rawSig = ''; +ksort($_POST, SORT_STRING); + +foreach ($_POST as $key => $value) { + if ($key === 'sig') continue; + $rawSig .= $value; +} + +$rawSig .= hash('sha512', decrypt($server->password)); +$signature = hash('sha256', $rawSig); + +if ($_POST['sig'] != $signature) { + http_response_code(403); + exit('Invalid signature'); +} + +$params = array( + 'serverusername' => $server->username, + 'serverpassword' => decrypt($server->password), + 'action' => 'Label', + 'label' => 'WHMCS ' . $service->id, + 'model' => $service +); +ArkhostVPSAG_API($params); + +if (gettype($_POST['ips']) !== 'array') $_POST['ips'] = json_decode($_POST['ips'], true); + +$_POST['ips'] = array_map(function ($ip) { + return $ip['ip']; +}, $_POST['ips']); + +$mainIP = $_POST['mainip']; + +$_POST['ips'] = array_filter($_POST['ips'], function ($ip) use ($mainIP) { + return $ip !== $mainIP; +}); + +Capsule::table('tblhosting')->where('id', $service->id)->update(array( + 'username' => $_POST['username'], + 'password' => encrypt($_POST['root']), + 'dedicatedip' => $mainIP, + 'assignedips' => (!array_shift($_POST['ips']) ? $_POST['ipv6'] : implode('\n', $_POST['ips']) . '\n' . $_POST['ipv6']), +)); + +echo '*ok*'; diff --git a/modules/servers/ArkhostVPSAG/lang/dutch.php b/modules/servers/ArkhostVPSAG/lang/dutch.php new file mode 100644 index 0000000..8ba5fa3 --- /dev/null +++ b/modules/servers/ArkhostVPSAG/lang/dutch.php @@ -0,0 +1,139 @@ +** De geautomatiseerde back-ups zullen ook uw handmatige back-ups vervangen, tenzij de geautomatiseerde back-ups zijn uitgeschakeld.
*** De geautomatiseerde back-ups worden 2 keer per week gemaakt en maken deel uit van ons noodherstelplan. Als u de geautomatiseerde back-ups uitschakelt, schakelt u ook elke kans op herstel in geval van een ramp uit.
**** Het bestandssysteem van de back-up is mogelijk niet volledig consistent als de VPS op het moment van de back-up naar het bestandssysteem schreef. Voor volledig consistente back-ups moet de server worden gestopt terwijl de back-up wordt gemaakt.'; +$_ADDONLANG['Backups']['Date'] = 'Datum'; +$_ADDONLANG['Backups']['Size'] = 'Grootte'; +$_ADDONLANG['Backups']['Type'] = 'Type'; +$_ADDONLANG['Backups']['Status'] = 'Status'; +$_ADDONLANG['Backups']['Actions'] = 'Acties'; +$_ADDONLANG['Backups']['Create'] = 'Nu Back-up Maken'; +$_ADDONLANG['Backups']['Available'] = 'Beschikbaar'; +$_ADDONLANG['Backups']['Creating'] = 'Bezig met maken...'; +$_ADDONLANG['Backups']['Error'] = 'Fout'; +$_ADDONLANG['Backups']['Automatic'] = 'Automatisch'; +$_ADDONLANG['Backups']['Manual'] = 'Handmatig'; + +## Instellingen +### Hostnaam +$_ADDONLANG['Settings']['Hostname']['Title'] = 'Hostnaam'; +$_ADDONLANG['Settings']['Hostname']['Description'] = 'Stelt de hostnaam en de rDNS in. Maak eerst het A-record aan.'; +$_ADDONLANG['Settings']['Hostname']['Submit'] = 'Verzenden'; + +### ISO +$_ADDONLANG['Settings']['ISO']['Title'] = 'ISO'; +$_ADDONLANG['Settings']['ISO']['Description'] = 'Als u het besturingssysteem via het ISO-image installeert, moet u ook de netwerkinterface statisch configureren. Er draait geen DHCP-server.'; +$_ADDONLANG['Settings']['ISO']['Image'] = 'ISO-image'; +$_ADDONLANG['Settings']['ISO']['Submit'] = 'ISO Laden'; +$_ADDONLANG['Settings']['ISO']['Remove'] = 'ISO Uitwerpen'; + +### Wachtwoord +$_ADDONLANG['Settings']['Password']['Title'] = 'Wachtwoord'; +$_ADDONLANG['Settings']['Password']['Description'] = 'Het installatiewachtwoord wordt na 72 uur uit onze systemen verwijderd. Het is verplicht om het wachtwoord bij uw eerste aanmelding te wijzigen!'; +$_ADDONLANG['Settings']['Password']['Submit'] = 'Wachtwoord Resetten'; + +### Herinstalleren +$_ADDONLANG['Settings']['Reinstall']['Title'] = 'Herinstalleren'; +$_ADDONLANG['Settings']['Reinstall']['Description'] = 'Begrijp alstublieft dat bij het herinstalleren alle gegevens van de server worden gewist. Deze actie is onomkeerbaar!'; +$_ADDONLANG['Settings']['Reinstall']['OS'] = 'Besturingssysteem'; +$_ADDONLANG['Settings']['Reinstall']['Version'] = 'KIES VERSIE'; +$_ADDONLANG['Settings']['Reinstall']['Submit'] = 'Herinstalleren'; +$_ADDONLANG['Settings']['Reinstall']['SSHKey'] = 'SSH Publieke Sleutel (optioneel)'; +$_ADDONLANG['Settings']['Reinstall']['SSHKeyDesc'] = 'Plak hier uw openbare SSH-sleutel (begint met ssh-rsa, ssh-ed25519, etc.). Deze wordt automatisch toegevoegd aan ~/.ssh/authorized_keys voor wachtwoordloos inloggen.'; +$_ADDONLANG['Settings']['Reinstall']['PostScript'] = 'Post-installatiescript (optioneel)'; +$_ADDONLANG['Settings']['Reinstall']['PostScriptDesc'] = 'Voer een bash-script in dat automatisch wordt uitgevoerd nadat de OS-installatie is voltooid. Handig voor het installeren van pakketten, het configureren van services of het instellen van uw omgeving.'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPassword'] = 'SSH-wachtwoordauthenticatie uitschakelen'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPasswordDesc'] = 'Indien ingeschakeld, is alleen SSH-sleutelauthenticatie toegestaan. Inloggen met wachtwoord via SSH wordt uitgeschakeld voor verbeterde beveiliging.'; + +### Firewall +$_ADDONLANG['Settings']['Firewall']['Title'] = 'Firewall'; +$_ADDONLANG['Settings']['Firewall']['Description'] = 'De regels worden van boven naar beneden geëvalueerd. Standaard is alles toegestaan. De firewall is alleen beschikbaar op de openbare interface. Alleen het inkomende verkeer wordt door de firewall gefilterd.'; +$_ADDONLANG['Settings']['Firewall']['AddNewRule'] = 'Nieuwe Firewallregel Toevoegen'; +$_ADDONLANG['Settings']['Firewall']['CurrentRules'] = 'Huidige Firewallregels'; +$_ADDONLANG['Settings']['Firewall']['AddRule'] = 'Regel Toevoegen'; +$_ADDONLANG['Settings']['Firewall']['Action'] = 'Actie'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Poort'; +$_ADDONLANG['Settings']['Firewall']['Protocol'] = 'Protocol'; +$_ADDONLANG['Settings']['Firewall']['Source'] = 'Bron'; +$_ADDONLANG['Settings']['Firewall']['Note'] = 'Notitie'; +$_ADDONLANG['Settings']['Firewall']['Actions'] = 'Acties'; +$_ADDONLANG['Settings']['Firewall']['Accept'] = 'Accepteren'; +$_ADDONLANG['Settings']['Firewall']['Drop'] = 'Weigeren'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Poortnummer'; +$_ADDONLANG['Settings']['Firewall']['SourceLabel'] = 'Bijv: x.x.x.x/xx (optioneel)'; +$_ADDONLANG['Settings']['Firewall']['Notes'] = 'Notities (optioneel)'; +$_ADDONLANG['Settings']['Firewall']['Warning'] = 'De regels moeten worden toegepast om van kracht te worden.'; +$_ADDONLANG['Settings']['Firewall']['Submit'] = 'Firewall Toepassen'; + +if (file_exists(__DIR__ . '/overrides/english.php')) include_once(__DIR__ . '/overrides/english.php'); diff --git a/modules/servers/ArkhostVPSAG/lang/english.php b/modules/servers/ArkhostVPSAG/lang/english.php new file mode 100644 index 0000000..a25b84a --- /dev/null +++ b/modules/servers/ArkhostVPSAG/lang/english.php @@ -0,0 +1,139 @@ +** The automated backups will also replace your manual backups unless the automated backups are disabled.
*** The automated backups are made 2 times a week and are part of our disaster recovery plan. If you disable the automated backups, you also disable any chance of recovery in case of a disaster.
**** The backup\'s file system might not be fully consistent if the VPS was writing to the filesystem at the moment of the backup. For fully consistent backups, the server must be stopped while the backup is being created.'; +$_ADDONLANG['Backups']['Date'] = 'Date'; +$_ADDONLANG['Backups']['Size'] = 'Size'; +$_ADDONLANG['Backups']['Type'] = 'Type'; +$_ADDONLANG['Backups']['Status'] = 'Status'; +$_ADDONLANG['Backups']['Actions'] = 'Actions'; +$_ADDONLANG['Backups']['Create'] = 'Backup Now'; +$_ADDONLANG['Backups']['Available'] = 'Available'; +$_ADDONLANG['Backups']['Creating'] = 'Creating...'; +$_ADDONLANG['Backups']['Error'] = 'Error'; +$_ADDONLANG['Backups']['Automatic'] = 'Automatic'; +$_ADDONLANG['Backups']['Manual'] = 'Manual'; + +## Settings +### Hostname +$_ADDONLANG['Settings']['Hostname']['Title'] = 'Hostname'; +$_ADDONLANG['Settings']['Hostname']['Description'] = 'Sets the hostname and the rDNS. Please create the A record first.'; +$_ADDONLANG['Settings']['Hostname']['Submit'] = 'Submit'; + +### ISO +$_ADDONLANG['Settings']['ISO']['Title'] = 'ISO'; +$_ADDONLANG['Settings']['ISO']['Description'] = 'If you install the operating system via the ISO image, you must also configure the network interface statically. There is no DHCP server running.'; +$_ADDONLANG['Settings']['ISO']['Image'] = 'ISO Image'; +$_ADDONLANG['Settings']['ISO']['Submit'] = 'Load ISO'; +$_ADDONLANG['Settings']['ISO']['Remove'] = 'Eject ISO'; + +### Password +$_ADDONLANG['Settings']['Password']['Title'] = 'Password'; +$_ADDONLANG['Settings']['Password']['Description'] = 'The installation password is removed from our systems after 72 hours. It is mandatory for you to change the password on your first login!'; +$_ADDONLANG['Settings']['Password']['Submit'] = 'Reset Password'; + +### Reinstall +$_ADDONLANG['Settings']['Reinstall']['Title'] = 'Reinstall'; +$_ADDONLANG['Settings']['Reinstall']['Description'] = 'Please understand that by reinstalling, all the data will be wiped from the server. This action is irreversible!'; +$_ADDONLANG['Settings']['Reinstall']['OS'] = 'Operating System'; +$_ADDONLANG['Settings']['Reinstall']['Version'] = 'CHOOSE VERSION'; +$_ADDONLANG['Settings']['Reinstall']['Submit'] = 'Reinstall'; +$_ADDONLANG['Settings']['Reinstall']['SSHKey'] = 'SSH Public Key (optional)'; +$_ADDONLANG['Settings']['Reinstall']['SSHKeyDesc'] = 'Paste your SSH public key here (starts with ssh-rsa, ssh-ed25519, etc.). This will be automatically added to ~/.ssh/authorized_keys for passwordless login.'; +$_ADDONLANG['Settings']['Reinstall']['PostScript'] = 'Post-Installation Script (optional)'; +$_ADDONLANG['Settings']['Reinstall']['PostScriptDesc'] = 'Enter a bash script to automatically run after the OS installation completes. Useful for installing packages, configuring services, or setting up your environment.'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPassword'] = 'Disable SSH password authentication'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPasswordDesc'] = 'When enabled, only SSH key authentication will be allowed. Password login via SSH will be disabled for enhanced security.'; + +### Firewall +$_ADDONLANG['Settings']['Firewall']['Title'] = 'Firewall'; +$_ADDONLANG['Settings']['Firewall']['Description'] = 'The rules are evaluated from the top to the bottom. By default, everything is allowed. The firewall is only available on the public interface. Only the inbound traffic will be filtered by the firewall.'; +$_ADDONLANG['Settings']['Firewall']['AddNewRule'] = 'Add New Firewall Rule'; +$_ADDONLANG['Settings']['Firewall']['CurrentRules'] = 'Current Firewall Rules'; +$_ADDONLANG['Settings']['Firewall']['AddRule'] = 'Add Rule'; +$_ADDONLANG['Settings']['Firewall']['Action'] = 'Action'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Port'; +$_ADDONLANG['Settings']['Firewall']['Protocol'] = 'Protocol'; +$_ADDONLANG['Settings']['Firewall']['Source'] = 'Source'; +$_ADDONLANG['Settings']['Firewall']['Note'] = 'Note'; +$_ADDONLANG['Settings']['Firewall']['Actions'] = 'Actions'; +$_ADDONLANG['Settings']['Firewall']['Accept'] = 'Accept'; +$_ADDONLANG['Settings']['Firewall']['Drop'] = 'Drop'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Port Number'; +$_ADDONLANG['Settings']['Firewall']['SourceLabel'] = 'Ex: x.x.x.x/xx (optional)'; +$_ADDONLANG['Settings']['Firewall']['Notes'] = 'Notes (optional)'; +$_ADDONLANG['Settings']['Firewall']['Warning'] = 'The rules must be committed in order to take effect.'; +$_ADDONLANG['Settings']['Firewall']['Submit'] = 'Commit Firewall'; + +if (file_exists(__DIR__ . '/overrides/english.php')) include_once(__DIR__ . '/overrides/english.php'); \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/lang/french.php b/modules/servers/ArkhostVPSAG/lang/french.php new file mode 100644 index 0000000..dc68443 --- /dev/null +++ b/modules/servers/ArkhostVPSAG/lang/french.php @@ -0,0 +1,139 @@ +** Les sauvegardes automatiques remplaceront également vos sauvegardes manuelles à moins que les sauvegardes automatiques ne soient désactivées.
*** Les sauvegardes automatiques sont effectuées 2 fois par semaine et font partie de notre plan de récupération après sinistre. Si vous désactivez les sauvegardes automatiques, vous désactivez également toute chance de récupération en cas de sinistre.
**** Le système de fichiers de la sauvegarde pourrait ne pas être entièrement cohérent si le VPS écrivait sur le système de fichiers au moment de la sauvegarde. Pour des sauvegardes entièrement cohérentes, le serveur doit être arrêté pendant que la sauvegarde est créée.'; +$_ADDONLANG['Backups']['Date'] = 'Date'; +$_ADDONLANG['Backups']['Size'] = 'Taille'; +$_ADDONLANG['Backups']['Type'] = 'Type'; +$_ADDONLANG['Backups']['Status'] = 'État'; +$_ADDONLANG['Backups']['Actions'] = 'Actions'; +$_ADDONLANG['Backups']['Create'] = 'Sauvegarder maintenant'; +$_ADDONLANG['Backups']['Available'] = 'Disponible'; +$_ADDONLANG['Backups']['Creating'] = 'Création...'; +$_ADDONLANG['Backups']['Error'] = 'Erreur'; +$_ADDONLANG['Backups']['Automatic'] = 'Automatique'; +$_ADDONLANG['Backups']['Manual'] = 'Manuel'; + +## Settings +### Hostname +$_ADDONLANG['Settings']['Hostname']['Title'] = 'Nom d\'hôte'; +$_ADDONLANG['Settings']['Hostname']['Description'] = 'Définit le nom d\'hôte et le rDNS. Veuillez d\'abord créer l\'enregistrement A.'; +$_ADDONLANG['Settings']['Hostname']['Submit'] = 'Soumettre'; + +### ISO +$_ADDONLANG['Settings']['ISO']['Title'] = 'ISO'; +$_ADDONLANG['Settings']['ISO']['Description'] = 'Si vous installez le système d\'exploitation via l\'image ISO, vous devez également configurer l\'interface réseau de manière statique. Il n\'y a pas de serveur DHCP en cours d\'exécution.'; +$_ADDONLANG['Settings']['ISO']['Image'] = 'Image ISO'; +$_ADDONLANG['Settings']['ISO']['Submit'] = 'Charger ISO'; +$_ADDONLANG['Settings']['ISO']['Remove'] = 'Éjecter ISO'; + +### Password +$_ADDONLANG['Settings']['Password']['Title'] = 'Mot de passe'; +$_ADDONLANG['Settings']['Password']['Description'] = 'Le mot de passe d\'installation est supprimé de nos systèmes après 72 heures. Il est obligatoire de changer le mot de passe lors de votre première connexion !'; +$_ADDONLANG['Settings']['Password']['Submit'] = 'Réinitialiser le mot de passe'; + +### Reinstall +$_ADDONLANG['Settings']['Reinstall']['Title'] = 'Réinstaller'; +$_ADDONLANG['Settings']['Reinstall']['Description'] = 'Veuillez comprendre qu\'en réinstallant, toutes les données seront effacées du serveur. Cette action est irréversible !'; +$_ADDONLANG['Settings']['Reinstall']['OS'] = 'Système d\'exploitation'; +$_ADDONLANG['Settings']['Reinstall']['Version'] = 'CHOISIR LA VERSION'; +$_ADDONLANG['Settings']['Reinstall']['Submit'] = 'Réinstaller'; +$_ADDONLANG['Settings']['Reinstall']['SSHKey'] = 'Clé publique SSH (optionnel)'; +$_ADDONLANG['Settings']['Reinstall']['SSHKeyDesc'] = 'Ajouter votre clé SSH pour connexion sans mot de passe'; +$_ADDONLANG['Settings']['Reinstall']['PostScript'] = 'Script post-installation (optionnel)'; +$_ADDONLANG['Settings']['Reinstall']['PostScriptDesc'] = 'Script bash à exécuter après l\'installation du SE'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPassword'] = 'Désactiver connexion SSH par mot de passe'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPasswordDesc'] = 'Autoriser uniquement l\'authentification par clé SSH'; + +### Firewall +$_ADDONLANG['Settings']['Firewall']['Title'] = 'Pare-feu'; +$_ADDONLANG['Settings']['Firewall']['Description'] = 'Les règles sont évaluées de haut en bas. Par défaut, tout est autorisé. Le pare-feu n\'est disponible que sur l\'interface publique. Seul le trafic entrant sera filtré par le pare-feu.'; +$_ADDONLANG['Settings']['Firewall']['AddNewRule'] = 'Ajouter une nouvelle règle de pare-feu'; +$_ADDONLANG['Settings']['Firewall']['CurrentRules'] = 'Règles de pare-feu actuelles'; +$_ADDONLANG['Settings']['Firewall']['AddRule'] = 'Ajouter une règle'; +$_ADDONLANG['Settings']['Firewall']['Action'] = 'Action'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Port'; +$_ADDONLANG['Settings']['Firewall']['Protocol'] = 'Protocole'; +$_ADDONLANG['Settings']['Firewall']['Source'] = 'Source'; +$_ADDONLANG['Settings']['Firewall']['Note'] = 'Note'; +$_ADDONLANG['Settings']['Firewall']['Actions'] = 'Actions'; +$_ADDONLANG['Settings']['Firewall']['Accept'] = 'Accepter'; +$_ADDONLANG['Settings']['Firewall']['Drop'] = 'Rejeter'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Numéro de port'; +$_ADDONLANG['Settings']['Firewall']['SourceLabel'] = 'Ex : x.x.x.x/xx (optionnel)'; +$_ADDONLANG['Settings']['Firewall']['Notes'] = 'Notes (optionnel)'; +$_ADDONLANG['Settings']['Firewall']['Warning'] = 'Les règles doivent être validées pour prendre effet.'; +$_ADDONLANG['Settings']['Firewall']['Submit'] = 'Valider le pare-feu'; + +if (file_exists(__DIR__ . '/overrides/french.php')) include_once(__DIR__ . '/overrides/french.php'); \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/lang/german.php b/modules/servers/ArkhostVPSAG/lang/german.php new file mode 100644 index 0000000..2df3bb7 --- /dev/null +++ b/modules/servers/ArkhostVPSAG/lang/german.php @@ -0,0 +1,139 @@ +** Die automatischen Sicherungen ersetzen auch Ihre manuellen Sicherungen, es sei denn, die automatischen Sicherungen sind deaktiviert.
*** Die automatischen Sicherungen werden 2-mal pro Woche erstellt und sind Teil unseres Disaster-Recovery-Plans. Wenn Sie die automatischen Sicherungen deaktivieren, deaktivieren Sie auch jede Chance auf Wiederherstellung im Falle einer Katastrophe.
**** Das Dateisystem der Sicherung ist möglicherweise nicht vollständig konsistent, wenn der VPS zum Zeitpunkt der Sicherung in das Dateisystem schrieb. Für vollständig konsistente Sicherungen muss der Server gestoppt werden, während die Sicherung erstellt wird.'; +$_ADDONLANG['Backups']['Date'] = 'Datum'; +$_ADDONLANG['Backups']['Size'] = 'Größe'; +$_ADDONLANG['Backups']['Type'] = 'Typ'; +$_ADDONLANG['Backups']['Status'] = 'Status'; +$_ADDONLANG['Backups']['Actions'] = 'Aktionen'; +$_ADDONLANG['Backups']['Create'] = 'Jetzt sichern'; +$_ADDONLANG['Backups']['Available'] = 'Verfügbar'; +$_ADDONLANG['Backups']['Creating'] = 'Erstellen...'; +$_ADDONLANG['Backups']['Error'] = 'Fehler'; +$_ADDONLANG['Backups']['Automatic'] = 'Automatisch'; +$_ADDONLANG['Backups']['Manual'] = 'Manuell'; + +## Settings +### Hostname +$_ADDONLANG['Settings']['Hostname']['Title'] = 'Hostname'; +$_ADDONLANG['Settings']['Hostname']['Description'] = 'Setzt den Hostnamen und das rDNS. Bitte erstellen Sie zuerst den A-Record.'; +$_ADDONLANG['Settings']['Hostname']['Submit'] = 'Absenden'; + +### ISO +$_ADDONLANG['Settings']['ISO']['Title'] = 'ISO'; +$_ADDONLANG['Settings']['ISO']['Description'] = 'Wenn Sie das Betriebssystem über das ISO-Image installieren, müssen Sie auch die Netzwerkschnittstelle statisch konfigurieren. Es läuft kein DHCP-Server.'; +$_ADDONLANG['Settings']['ISO']['Image'] = 'ISO-Image'; +$_ADDONLANG['Settings']['ISO']['Submit'] = 'ISO laden'; +$_ADDONLANG['Settings']['ISO']['Remove'] = 'ISO auswerfen'; + +### Password +$_ADDONLANG['Settings']['Password']['Title'] = 'Passwort'; +$_ADDONLANG['Settings']['Password']['Description'] = 'Das Installationspasswort wird nach 72 Stunden aus unseren Systemen entfernt. Sie müssen das Passwort bei Ihrer ersten Anmeldung ändern!'; +$_ADDONLANG['Settings']['Password']['Submit'] = 'Passwort zurücksetzen'; + +### Reinstall +$_ADDONLANG['Settings']['Reinstall']['Title'] = 'Neuinstallation'; +$_ADDONLANG['Settings']['Reinstall']['Description'] = 'Bitte verstehen Sie, dass durch die Neuinstallation alle Daten vom Server gelöscht werden. Diese Aktion ist unumkehrbar!'; +$_ADDONLANG['Settings']['Reinstall']['OS'] = 'Betriebssystem'; +$_ADDONLANG['Settings']['Reinstall']['Version'] = 'VERSION WÄHLEN'; +$_ADDONLANG['Settings']['Reinstall']['Submit'] = 'Neuinstallieren'; +$_ADDONLANG['Settings']['Reinstall']['SSHKey'] = 'SSH öffentlicher Schlüssel (optional)'; +$_ADDONLANG['Settings']['Reinstall']['SSHKeyDesc'] = 'Fügen Sie hier Ihren SSH-öffentlichen Schlüssel ein (beginnt mit ssh-rsa, ssh-ed25519, etc.). Dieser wird automatisch zu ~/.ssh/authorized_keys für passwortlose Anmeldung hinzugefügt.'; +$_ADDONLANG['Settings']['Reinstall']['PostScript'] = 'Post-Installations-Skript (optional)'; +$_ADDONLANG['Settings']['Reinstall']['PostScriptDesc'] = 'Geben Sie ein Bash-Skript ein, das automatisch nach Abschluss der OS-Installation ausgeführt wird. Nützlich für die Installation von Paketen, Konfiguration von Diensten oder Einrichtung Ihrer Umgebung.'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPassword'] = 'SSH-Passwort-Authentifizierung deaktivieren'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPasswordDesc'] = 'Wenn aktiviert, ist nur SSH-Schlüssel-Authentifizierung erlaubt. Passwort-Login über SSH wird für erhöhte Sicherheit deaktiviert.'; + +### Firewall +$_ADDONLANG['Settings']['Firewall']['Title'] = 'Firewall'; +$_ADDONLANG['Settings']['Firewall']['Description'] = 'Die Regeln werden von oben nach unten ausgewertet. Standardmäßig ist alles erlaubt. Die Firewall ist nur auf der öffentlichen Schnittstelle verfügbar. Nur der eingehende Verkehr wird von der Firewall gefiltert.'; +$_ADDONLANG['Settings']['Firewall']['AddNewRule'] = 'Neue Firewall-Regel hinzufügen'; +$_ADDONLANG['Settings']['Firewall']['CurrentRules'] = 'Aktuelle Firewall-Regeln'; +$_ADDONLANG['Settings']['Firewall']['AddRule'] = 'Regel hinzufügen'; +$_ADDONLANG['Settings']['Firewall']['Action'] = 'Aktion'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Port'; +$_ADDONLANG['Settings']['Firewall']['Protocol'] = 'Protokoll'; +$_ADDONLANG['Settings']['Firewall']['Source'] = 'Quelle'; +$_ADDONLANG['Settings']['Firewall']['Note'] = 'Notiz'; +$_ADDONLANG['Settings']['Firewall']['Actions'] = 'Aktionen'; +$_ADDONLANG['Settings']['Firewall']['Accept'] = 'Akzeptieren'; +$_ADDONLANG['Settings']['Firewall']['Drop'] = 'Verwerfen'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Port-Nummer'; +$_ADDONLANG['Settings']['Firewall']['SourceLabel'] = 'Bsp: x.x.x.x/xx (optional)'; +$_ADDONLANG['Settings']['Firewall']['Notes'] = 'Notizen (optional)'; +$_ADDONLANG['Settings']['Firewall']['Warning'] = 'Die Regeln müssen übernommen werden, um wirksam zu werden.'; +$_ADDONLANG['Settings']['Firewall']['Submit'] = 'Firewall übernehmen'; + +if (file_exists(__DIR__ . '/overrides/german.php')) include_once(__DIR__ . '/overrides/german.php'); \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/lang/italian.php b/modules/servers/ArkhostVPSAG/lang/italian.php new file mode 100644 index 0000000..ac0f24b --- /dev/null +++ b/modules/servers/ArkhostVPSAG/lang/italian.php @@ -0,0 +1,139 @@ +** I backup automatici sostituiranno anche i tuoi backup manuali a meno che i backup automatici non siano disabilitati.
*** I backup automatici vengono eseguiti 2 volte a settimana e fanno parte del nostro piano di disaster recovery. Se disabiliti i backup automatici, disabiliti anche qualsiasi possibilità di recupero in caso di disastro.
**** Il file system del backup potrebbe non essere completamente coerente se il VPS stava scrivendo sul filesystem al momento del backup. Per backup completamente coerenti, il server deve essere fermato durante la creazione del backup.'; +$_ADDONLANG['Backups']['Date'] = 'Data'; +$_ADDONLANG['Backups']['Size'] = 'Dimensione'; +$_ADDONLANG['Backups']['Type'] = 'Tipo'; +$_ADDONLANG['Backups']['Status'] = 'Stato'; +$_ADDONLANG['Backups']['Actions'] = 'Azioni'; +$_ADDONLANG['Backups']['Create'] = 'Backup Ora'; +$_ADDONLANG['Backups']['Available'] = 'Disponibile'; +$_ADDONLANG['Backups']['Creating'] = 'Creazione...'; +$_ADDONLANG['Backups']['Error'] = 'Errore'; +$_ADDONLANG['Backups']['Automatic'] = 'Automatico'; +$_ADDONLANG['Backups']['Manual'] = 'Manuale'; + +## Settings +### Hostname +$_ADDONLANG['Settings']['Hostname']['Title'] = 'Hostname'; +$_ADDONLANG['Settings']['Hostname']['Description'] = 'Imposta l\'hostname e l\'rDNS. Crea prima il record A.'; +$_ADDONLANG['Settings']['Hostname']['Submit'] = 'Invia'; + +### ISO +$_ADDONLANG['Settings']['ISO']['Title'] = 'ISO'; +$_ADDONLANG['Settings']['ISO']['Description'] = 'Se installi il sistema operativo tramite l\'immagine ISO, devi anche configurare staticamente l\'interfaccia di rete. Non c\'è un server DHCP in esecuzione.'; +$_ADDONLANG['Settings']['ISO']['Image'] = 'Immagine ISO'; +$_ADDONLANG['Settings']['ISO']['Submit'] = 'Carica ISO'; +$_ADDONLANG['Settings']['ISO']['Remove'] = 'Espelli ISO'; + +### Password +$_ADDONLANG['Settings']['Password']['Title'] = 'Password'; +$_ADDONLANG['Settings']['Password']['Description'] = 'La password di installazione viene rimossa dai nostri sistemi dopo 72 ore. È obbligatorio cambiare la password al primo accesso!'; +$_ADDONLANG['Settings']['Password']['Submit'] = 'Reimposta Password'; + +### Reinstall +$_ADDONLANG['Settings']['Reinstall']['Title'] = 'Reinstalla'; +$_ADDONLANG['Settings']['Reinstall']['Description'] = 'Ti preghiamo di comprendere che reinstallando, tutti i dati saranno cancellati dal server. Questa azione è irreversibile!'; +$_ADDONLANG['Settings']['Reinstall']['OS'] = 'Sistema Operativo'; +$_ADDONLANG['Settings']['Reinstall']['Version'] = 'SCEGLI VERSIONE'; +$_ADDONLANG['Settings']['Reinstall']['Submit'] = 'Reinstalla'; +$_ADDONLANG['Settings']['Reinstall']['SSHKey'] = 'Chiave pubblica SSH (opzionale)'; +$_ADDONLANG['Settings']['Reinstall']['SSHKeyDesc'] = 'Aggiungi la tua chiave SSH per accesso senza password'; +$_ADDONLANG['Settings']['Reinstall']['PostScript'] = 'Script post-installazione (opzionale)'; +$_ADDONLANG['Settings']['Reinstall']['PostScriptDesc'] = 'Script bash da eseguire dopo l\'installazione del SO'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPassword'] = 'Disabilita login SSH con password'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPasswordDesc'] = 'Consenti solo autenticazione con chiave SSH'; + +### Firewall +$_ADDONLANG['Settings']['Firewall']['Title'] = 'Firewall'; +$_ADDONLANG['Settings']['Firewall']['Description'] = 'Le regole vengono valutate dall\'alto verso il basso. Per impostazione predefinita, tutto è consentito. Il firewall è disponibile solo sull\'interfaccia pubblica. Solo il traffico in entrata sarà filtrato dal firewall.'; +$_ADDONLANG['Settings']['Firewall']['AddNewRule'] = 'Aggiungi Nuova Regola Firewall'; +$_ADDONLANG['Settings']['Firewall']['CurrentRules'] = 'Regole Firewall Attuali'; +$_ADDONLANG['Settings']['Firewall']['AddRule'] = 'Aggiungi Regola'; +$_ADDONLANG['Settings']['Firewall']['Action'] = 'Azione'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Porta'; +$_ADDONLANG['Settings']['Firewall']['Protocol'] = 'Protocollo'; +$_ADDONLANG['Settings']['Firewall']['Source'] = 'Origine'; +$_ADDONLANG['Settings']['Firewall']['Note'] = 'Nota'; +$_ADDONLANG['Settings']['Firewall']['Actions'] = 'Azioni'; +$_ADDONLANG['Settings']['Firewall']['Accept'] = 'Accetta'; +$_ADDONLANG['Settings']['Firewall']['Drop'] = 'Scarta'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Numero Porta'; +$_ADDONLANG['Settings']['Firewall']['SourceLabel'] = 'Es: x.x.x.x/xx (opzionale)'; +$_ADDONLANG['Settings']['Firewall']['Notes'] = 'Note (opzionale)'; +$_ADDONLANG['Settings']['Firewall']['Warning'] = 'Le regole devono essere confermate per entrare in vigore.'; +$_ADDONLANG['Settings']['Firewall']['Submit'] = 'Conferma Firewall'; + +if (file_exists(__DIR__ . '/overrides/italian.php')) include_once(__DIR__ . '/overrides/italian.php'); \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/lang/overrides/index.php b/modules/servers/ArkhostVPSAG/lang/overrides/index.php new file mode 100644 index 0000000..75befd5 --- /dev/null +++ b/modules/servers/ArkhostVPSAG/lang/overrides/index.php @@ -0,0 +1,13 @@ + + * @link https://arkhost.com + */ + +http_response_code(403); +exit('Access denied'); +?> \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/lang/portuguese-pt.php b/modules/servers/ArkhostVPSAG/lang/portuguese-pt.php new file mode 100644 index 0000000..6e3473a --- /dev/null +++ b/modules/servers/ArkhostVPSAG/lang/portuguese-pt.php @@ -0,0 +1,139 @@ +** As cópias de segurança automáticas também irão substituir as suas cópias de segurança manuais, a menos que as cópias de segurança automáticas estejam desativadas.
*** As cópias de segurança automáticas são feitas 2 vezes por semana e fazem parte do nosso plano de recuperação de desastres. Se desativar as cópias de segurança automáticas, também desativa qualquer hipótese de recuperação em caso de desastre.
**** O sistema de ficheiros da cópia de segurança pode não estar totalmente consistente se o VPS estivesse a escrever no sistema de ficheiros no momento da cópia de segurança. Para cópias de segurança totalmente consistentes, o servidor deve ser parado enquanto a cópia de segurança está a ser criada.'; +$_ADDONLANG['Backups']['Date'] = 'Data'; +$_ADDONLANG['Backups']['Size'] = 'Tamanho'; +$_ADDONLANG['Backups']['Type'] = 'Tipo'; +$_ADDONLANG['Backups']['Status'] = 'Estado'; +$_ADDONLANG['Backups']['Actions'] = 'Ações'; +$_ADDONLANG['Backups']['Create'] = 'Criar cópia agora'; +$_ADDONLANG['Backups']['Available'] = 'Disponível'; +$_ADDONLANG['Backups']['Creating'] = 'Criando...'; +$_ADDONLANG['Backups']['Error'] = 'Erro'; +$_ADDONLANG['Backups']['Automatic'] = 'Automático'; +$_ADDONLANG['Backups']['Manual'] = 'Manual'; + +## Settings +### Hostname +$_ADDONLANG['Settings']['Hostname']['Title'] = 'Nome do anfitrião'; +$_ADDONLANG['Settings']['Hostname']['Description'] = 'Define o nome do anfitrião e o rDNS. Por favor, crie primeiro o registo A.'; +$_ADDONLANG['Settings']['Hostname']['Submit'] = 'Submeter'; + +### ISO +$_ADDONLANG['Settings']['ISO']['Title'] = 'ISO'; +$_ADDONLANG['Settings']['ISO']['Description'] = 'Se instalar o sistema operativo através da imagem ISO, também deve configurar a interface de rede estaticamente. Não há servidor DHCP em execução.'; +$_ADDONLANG['Settings']['ISO']['Image'] = 'Imagem ISO'; +$_ADDONLANG['Settings']['ISO']['Submit'] = 'Carregar ISO'; +$_ADDONLANG['Settings']['ISO']['Remove'] = 'Ejetar ISO'; + +### Password +$_ADDONLANG['Settings']['Password']['Title'] = 'Palavra-passe'; +$_ADDONLANG['Settings']['Password']['Description'] = 'A palavra-passe de instalação é removida dos nossos sistemas após 72 horas. É obrigatório alterar a palavra-passe no primeiro início de sessão!'; +$_ADDONLANG['Settings']['Password']['Submit'] = 'Redefinir palavra-passe'; + +### Reinstall +$_ADDONLANG['Settings']['Reinstall']['Title'] = 'Reinstalar'; +$_ADDONLANG['Settings']['Reinstall']['Description'] = 'Por favor, compreenda que ao reinstalar, todos os dados serão apagados do servidor. Esta ação é irreversível!'; +$_ADDONLANG['Settings']['Reinstall']['OS'] = 'Sistema operativo'; +$_ADDONLANG['Settings']['Reinstall']['Version'] = 'ESCOLHER VERSÃO'; +$_ADDONLANG['Settings']['Reinstall']['Submit'] = 'Reinstalar'; +$_ADDONLANG['Settings']['Reinstall']['SSHKey'] = 'Chave pública SSH (opcional)'; +$_ADDONLANG['Settings']['Reinstall']['SSHKeyDesc'] = 'Adicionar chave SSH para acesso sem palavra-passe'; +$_ADDONLANG['Settings']['Reinstall']['PostScript'] = 'Script pós-instalação (opcional)'; +$_ADDONLANG['Settings']['Reinstall']['PostScriptDesc'] = 'Script bash para executar após instalação do SO'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPassword'] = 'Desabilitar login SSH com palavra-passe'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPasswordDesc'] = 'Permitir apenas autenticação com chave SSH'; + +### Firewall +$_ADDONLANG['Settings']['Firewall']['Title'] = 'Firewall'; +$_ADDONLANG['Settings']['Firewall']['Description'] = 'As regras são avaliadas de cima para baixo. Por defeito, tudo é permitido. A firewall está apenas disponível na interface pública. Apenas o tráfego de entrada será filtrado pela firewall.'; +$_ADDONLANG['Settings']['Firewall']['AddNewRule'] = 'Adicionar Nova Regra de Firewall'; +$_ADDONLANG['Settings']['Firewall']['CurrentRules'] = 'Regras de Firewall Atuais'; +$_ADDONLANG['Settings']['Firewall']['AddRule'] = 'Adicionar Regra'; +$_ADDONLANG['Settings']['Firewall']['Action'] = 'Ação'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Porta'; +$_ADDONLANG['Settings']['Firewall']['Protocol'] = 'Protocolo'; +$_ADDONLANG['Settings']['Firewall']['Source'] = 'Origem'; +$_ADDONLANG['Settings']['Firewall']['Note'] = 'Nota'; +$_ADDONLANG['Settings']['Firewall']['Actions'] = 'Ações'; +$_ADDONLANG['Settings']['Firewall']['Accept'] = 'Aceitar'; +$_ADDONLANG['Settings']['Firewall']['Drop'] = 'Descartar'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Número da porta'; +$_ADDONLANG['Settings']['Firewall']['SourceLabel'] = 'Ex: x.x.x.x/xx (opcional)'; +$_ADDONLANG['Settings']['Firewall']['Notes'] = 'Notas (opcional)'; +$_ADDONLANG['Settings']['Firewall']['Warning'] = 'As regras devem ser confirmadas para entrarem em vigor.'; +$_ADDONLANG['Settings']['Firewall']['Submit'] = 'Confirmar firewall'; + +if (file_exists(__DIR__ . '/overrides/portuguese-pt.php')) include_once(__DIR__ . '/overrides/portuguese-pt.php'); \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/lang/russian.php b/modules/servers/ArkhostVPSAG/lang/russian.php new file mode 100644 index 0000000..0bef672 --- /dev/null +++ b/modules/servers/ArkhostVPSAG/lang/russian.php @@ -0,0 +1,139 @@ +** Автоматические резервные копии также заменят ваши ручные резервные копии, если автоматическое резервное копирование не отключено.
*** Автоматические резервные копии создаются 2 раза в неделю и являются частью нашего плана аварийного восстановления. Если вы отключите автоматическое резервное копирование, вы также отключите любую возможность восстановления в случае катастрофы.
**** Файловая система резервной копии может быть не полностью согласованной, если VPS записывал в файловую систему в момент создания резервной копии. Для полностью согласованных резервных копий сервер должен быть остановлен во время создания резервной копии.'; +$_ADDONLANG['Backups']['Date'] = 'Дата'; +$_ADDONLANG['Backups']['Size'] = 'Размер'; +$_ADDONLANG['Backups']['Type'] = 'Тип'; +$_ADDONLANG['Backups']['Status'] = 'Статус'; +$_ADDONLANG['Backups']['Actions'] = 'Действия'; +$_ADDONLANG['Backups']['Create'] = 'Создать резервную копию сейчас'; +$_ADDONLANG['Backups']['Available'] = 'Доступна'; +$_ADDONLANG['Backups']['Creating'] = 'Создание...'; +$_ADDONLANG['Backups']['Error'] = 'Ошибка'; +$_ADDONLANG['Backups']['Automatic'] = 'Автоматическая'; +$_ADDONLANG['Backups']['Manual'] = 'Ручная'; + +## Настройки +### Имя хоста +$_ADDONLANG['Settings']['Hostname']['Title'] = 'Имя хоста'; +$_ADDONLANG['Settings']['Hostname']['Description'] = 'Устанавливает имя хоста и обратную DNS-запись. Пожалуйста, сначала создайте запись A.'; +$_ADDONLANG['Settings']['Hostname']['Submit'] = 'Отправить'; + +### ISO +$_ADDONLANG['Settings']['ISO']['Title'] = 'ISO'; +$_ADDONLANG['Settings']['ISO']['Description'] = 'Если вы устанавливаете операционную систему через ISO-образ, вы также должны настроить сетевой интерфейс статически. DHCP-сервер не работает.'; +$_ADDONLANG['Settings']['ISO']['Image'] = 'ISO-образ'; +$_ADDONLANG['Settings']['ISO']['Submit'] = 'Загрузить ISO'; +$_ADDONLANG['Settings']['ISO']['Remove'] = 'Извлечь ISO'; + +### Пароль +$_ADDONLANG['Settings']['Password']['Title'] = 'Пароль'; +$_ADDONLANG['Settings']['Password']['Description'] = 'Пароль установки удаляется из наших систем через 72 часа. Обязательно смените пароль при первом входе в систему!'; +$_ADDONLANG['Settings']['Password']['Submit'] = 'Сбросить пароль'; + +### Переустановка +$_ADDONLANG['Settings']['Reinstall']['Title'] = 'Переустановка'; +$_ADDONLANG['Settings']['Reinstall']['Description'] = 'Пожалуйста, учтите, что при переустановке все данные будут удалены с сервера. Это действие необратимо!'; +$_ADDONLANG['Settings']['Reinstall']['OS'] = 'Операционная система'; +$_ADDONLANG['Settings']['Reinstall']['Version'] = 'ВЫБЕРИТЕ ВЕРСИЮ'; +$_ADDONLANG['Settings']['Reinstall']['Submit'] = 'Переустановить'; +$_ADDONLANG['Settings']['Reinstall']['SSHKey'] = 'Публичный SSH-ключ (необязательно)'; +$_ADDONLANG['Settings']['Reinstall']['SSHKeyDesc'] = 'Вставьте сюда свой публичный SSH-ключ (начинается с ssh-rsa, ssh-ed25519 и т.д.). Он будет автоматически добавлен в ~/.ssh/authorized_keys для входа без пароля.'; +$_ADDONLANG['Settings']['Reinstall']['PostScript'] = 'Скрипт после установки (необязательно)'; +$_ADDONLANG['Settings']['Reinstall']['PostScriptDesc'] = 'Введите bash-скрипт, который будет автоматически выполнен после завершения установки ОС. Полезно для установки пакетов, настройки служб или настройки вашей среды.'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPassword'] = 'Отключить аутентификацию по паролю SSH'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPasswordDesc'] = 'Если включено, разрешена только аутентификация по SSH-ключу. Вход по паролю через SSH будет отключен для повышенной безопасности.'; + +### Файрвол +$_ADDONLANG['Settings']['Firewall']['Title'] = 'Файрвол'; +$_ADDONLANG['Settings']['Firewall']['Description'] = 'Правила оцениваются сверху вниз. По умолчанию разрешено все. Файрвол доступен только на публичном интерфейсе. Файрвол будет фильтровать только входящий трафик.'; +$_ADDONLANG['Settings']['Firewall']['AddNewRule'] = 'Добавить новое правило файрвола'; +$_ADDONLANG['Settings']['Firewall']['CurrentRules'] = 'Текущие правила файрвола'; +$_ADDONLANG['Settings']['Firewall']['AddRule'] = 'Добавить правило'; +$_ADDONLANG['Settings']['Firewall']['Action'] = 'Действие'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Порт'; +$_ADDONLANG['Settings']['Firewall']['Protocol'] = 'Протокол'; +$_ADDONLANG['Settings']['Firewall']['Source'] = 'Источник'; +$_ADDONLANG['Settings']['Firewall']['Note'] = 'Примечание'; +$_ADDONLANG['Settings']['Firewall']['Actions'] = 'Действия'; +$_ADDONLANG['Settings']['Firewall']['Accept'] = 'Принять'; +$_ADDONLANG['Settings']['Firewall']['Drop'] = 'Отклонить'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Номер порта'; +$_ADDONLANG['Settings']['Firewall']['SourceLabel'] = 'Пример: x.x.x.x/xx (необязательно)'; +$_ADDONLANG['Settings']['Firewall']['Notes'] = 'Примечания (необязательно)'; +$_ADDONLANG['Settings']['Firewall']['Warning'] = 'Правила должны быть применены, чтобы вступить в силу.'; +$_ADDONLANG['Settings']['Firewall']['Submit'] = 'Применить файрвол'; + +if (file_exists(__DIR__ . '/overrides/english.php')) include_once(__DIR__ . '/overrides/english.php'); diff --git a/modules/servers/ArkhostVPSAG/lang/spanish.php b/modules/servers/ArkhostVPSAG/lang/spanish.php new file mode 100644 index 0000000..25544e2 --- /dev/null +++ b/modules/servers/ArkhostVPSAG/lang/spanish.php @@ -0,0 +1,139 @@ +** Las copias de seguridad automáticas también reemplazarán sus copias de seguridad manuales a menos que las copias de seguridad automáticas estén deshabilitadas.
*** Las copias de seguridad automáticas se realizan 2 veces por semana y son parte de nuestro plan de recuperación ante desastres. Si deshabilita las copias de seguridad automáticas, también deshabilita cualquier posibilidad de recuperación en caso de desastre.
**** El sistema de archivos de la copia de seguridad podría no estar completamente consistente si el VPS estaba escribiendo en el sistema de archivos en el momento de la copia de seguridad. Para copias de seguridad completamente consistentes, el servidor debe detenerse mientras se crea la copia de seguridad.'; +$_ADDONLANG['Backups']['Date'] = 'Fecha'; +$_ADDONLANG['Backups']['Size'] = 'Tamaño'; +$_ADDONLANG['Backups']['Type'] = 'Tipo'; +$_ADDONLANG['Backups']['Status'] = 'Estado'; +$_ADDONLANG['Backups']['Actions'] = 'Acciones'; +$_ADDONLANG['Backups']['Create'] = 'Crear copia ahora'; +$_ADDONLANG['Backups']['Available'] = 'Disponible'; +$_ADDONLANG['Backups']['Creating'] = 'Creando...'; +$_ADDONLANG['Backups']['Error'] = 'Error'; +$_ADDONLANG['Backups']['Automatic'] = 'Automático'; +$_ADDONLANG['Backups']['Manual'] = 'Manual'; + +## Settings +### Hostname +$_ADDONLANG['Settings']['Hostname']['Title'] = 'Nombre del host'; +$_ADDONLANG['Settings']['Hostname']['Description'] = 'Establece el nombre del host y el rDNS. Cree primero el registro A.'; +$_ADDONLANG['Settings']['Hostname']['Submit'] = 'Enviar'; + +### ISO +$_ADDONLANG['Settings']['ISO']['Title'] = 'ISO'; +$_ADDONLANG['Settings']['ISO']['Description'] = 'Si instala el sistema operativo a través de la imagen ISO, también debe configurar la interfaz de red estáticamente. No hay un servidor DHCP ejecutándose.'; +$_ADDONLANG['Settings']['ISO']['Image'] = 'Imagen ISO'; +$_ADDONLANG['Settings']['ISO']['Submit'] = 'Cargar ISO'; +$_ADDONLANG['Settings']['ISO']['Remove'] = 'Expulsar ISO'; + +### Password +$_ADDONLANG['Settings']['Password']['Title'] = 'Contraseña'; +$_ADDONLANG['Settings']['Password']['Description'] = 'La contraseña de instalación se elimina de nuestros sistemas después de 72 horas. ¡Es obligatorio cambiar la contraseña en su primer inicio de sesión!'; +$_ADDONLANG['Settings']['Password']['Submit'] = 'Restablecer contraseña'; + +### Reinstall +$_ADDONLANG['Settings']['Reinstall']['Title'] = 'Reinstalar'; +$_ADDONLANG['Settings']['Reinstall']['Description'] = 'Por favor entienda que al reinstalar, todos los datos se borrarán del servidor. ¡Esta acción es irreversible!'; +$_ADDONLANG['Settings']['Reinstall']['OS'] = 'Sistema operativo'; +$_ADDONLANG['Settings']['Reinstall']['Version'] = 'ELEGIR VERSIÓN'; +$_ADDONLANG['Settings']['Reinstall']['Submit'] = 'Reinstalar'; +$_ADDONLANG['Settings']['Reinstall']['SSHKey'] = 'Clave pública SSH (opcional)'; +$_ADDONLANG['Settings']['Reinstall']['SSHKeyDesc'] = 'Añadir clave SSH para acceso sin contraseña'; +$_ADDONLANG['Settings']['Reinstall']['PostScript'] = 'Script post-instalación (opcional)'; +$_ADDONLANG['Settings']['Reinstall']['PostScriptDesc'] = 'Script bash a ejecutar después de la instalación del SO'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPassword'] = 'Deshabilitar login SSH con contraseña'; +$_ADDONLANG['Settings']['Reinstall']['DisableSSHPasswordDesc'] = 'Solo permitir autenticación con clave SSH'; + +### Firewall +$_ADDONLANG['Settings']['Firewall']['Title'] = 'Firewall'; +$_ADDONLANG['Settings']['Firewall']['Description'] = 'Las reglas se evalúan de arriba hacia abajo. Por defecto, todo está permitido. El firewall solo está disponible en la interfaz pública. Solo el tráfico entrante será filtrado por el firewall.'; +$_ADDONLANG['Settings']['Firewall']['AddNewRule'] = 'Agregar Nueva Regla de Firewall'; +$_ADDONLANG['Settings']['Firewall']['CurrentRules'] = 'Reglas de Firewall Actuales'; +$_ADDONLANG['Settings']['Firewall']['AddRule'] = 'Agregar Regla'; +$_ADDONLANG['Settings']['Firewall']['Action'] = 'Acción'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Puerto'; +$_ADDONLANG['Settings']['Firewall']['Protocol'] = 'Protocolo'; +$_ADDONLANG['Settings']['Firewall']['Source'] = 'Origen'; +$_ADDONLANG['Settings']['Firewall']['Note'] = 'Nota'; +$_ADDONLANG['Settings']['Firewall']['Actions'] = 'Acciones'; +$_ADDONLANG['Settings']['Firewall']['Accept'] = 'Aceptar'; +$_ADDONLANG['Settings']['Firewall']['Drop'] = 'Descartar'; +$_ADDONLANG['Settings']['Firewall']['Port'] = 'Número de puerto'; +$_ADDONLANG['Settings']['Firewall']['SourceLabel'] = 'Ej: x.x.x.x/xx (opcional)'; +$_ADDONLANG['Settings']['Firewall']['Notes'] = 'Notas (opcional)'; +$_ADDONLANG['Settings']['Firewall']['Warning'] = 'Las reglas deben confirmarse para que surtan efecto.'; +$_ADDONLANG['Settings']['Firewall']['Submit'] = 'Confirmar firewall'; + +if (file_exists(__DIR__ . '/overrides/spanish.php')) include_once(__DIR__ . '/overrides/spanish.php'); \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/logo.png b/modules/servers/ArkhostVPSAG/logo.png new file mode 100644 index 0000000..05df953 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/logo.png differ diff --git a/modules/servers/ArkhostVPSAG/template/clientarea_direct.tpl b/modules/servers/ArkhostVPSAG/template/clientarea_direct.tpl new file mode 100644 index 0000000..c50d00b --- /dev/null +++ b/modules/servers/ArkhostVPSAG/template/clientarea_direct.tpl @@ -0,0 +1,2098 @@ +{* + * WHMCS Server Module - VPSAG + * @package WHMCS + * @copyright ArkHost 2025 + * @link https://arkhost.com + * @author ArkHost + *} + + + + + + + +
+ + +
+
+ +
+
+ +
+
+
{$_LANG['Overview']['ServerInfo']}
+
+
+
+
+ + + + + + + + + + {if $serverInfo['ipv6']} + + + + + {/if} + + + + +
{$_LANG['Overview']['Hostname']}:{$serverInfo['hostname']|default:'N/A'}
{$_LANG['IPv4']} Address:{$serverInfo['ip']}
{$_LANG['IPv6']} Address:{$serverInfo['ipv6']}
{$_LANG['Overview']['OS']}: + {if $serverInfo['operatingSystem']['image']} + + {/if} + {$serverInfo['operatingSystem']['name']|default:'N/A'} +
+
+
+ + + + + + + + + + + + + +
{$_LANG['Overview']['Status']}: + + + {$serverInfo['statusDescription']} + +
{$_LANG['Overview']['Uptime']}:{$serverInfo['uptime_text']|default:'N/A'}
{$_LANG['Overview']['ServerType']}:{$serverInfo['server_type']|default:'Standard'}
+
+
+
+
+ + +
+
+
{$_LANG['Overview']['ResourceAllocation']}
+
+
+
+
+
+ +

{$serverInfo['cpu']|default:'N/A'}

+ {$_LANG['Overview']['CPU_Cores']} +
+
+
+
+ +

{$serverInfo['ram']|default:'N/A'} {$_LANG['General']['GB']}

+ {$_LANG['Overview']['Memory']} +
+
+
+
+ +

{$serverInfo['disk']|default:'N/A'} {$_LANG['General']['GB']}

+ {$_LANG['Overview']['Storage']} +
+
+
+
+ +

{$serverInfo['bandwidth']|default:'20'} {$_LANG['General']['TB']}

+ {$_LANG['Overview']['Traffic']} +
+
+
+
+
+ + +
+
+
{$_LANG['Overview']['ResourceUsage']}
+
+
+
+
+
+

+ {$_LANG['Overview']['RAM']} + +

+
+
+ {if $serverInfo['ram'] > 0}{($serverInfo['ram_usage']/1024/1024/1024/$serverInfo['ram']*100)|round}{else}0{/if}% +
+
+
+ {($serverInfo['ram_usage']/1024/1024/1024)|round:1} / {$serverInfo['ram']} GB + {$_LANG['Used']} +
+
+
+
+
+

+ Bandwidth + +

+
+
+ {if $serverInfo['bandwidth'] > 0}{($serverInfo['bandwidth_used']/1024/$serverInfo['bandwidth']*100)|round}{else}0{/if}% +
+
+
+ {($serverInfo['bandwidth_used']/1024)|round:1} / {$serverInfo['bandwidth']} TB + {$_LANG['Used']} +
+
+
+
+
+

+ {$_LANG['Overview']['CPU']} + +

+
+
+ {if $serverInfo['cpu_usage'] <= 1}{($serverInfo['cpu_usage'] * 100)|round}{else}{$serverInfo['cpu_usage']|ceil}{/if}% +
+
+
+ {if $serverInfo['cpu_usage'] <= 1}{($serverInfo['cpu_usage'] * 100)|round}{else}{$serverInfo['cpu_usage']|ceil}{/if}% {$_LANG['Overview']['CPUUsage']} + +
+
+
+
+
+
+ + +
+
+
{$_LANG['Overview']['QuickActions']}
+
+
+
+ + + + {$_LANG['VNC']} + +
+
+
+
+ +
+
+ + {$_LANG['Navbar']['Graphs']} +
+ + +
+
+ + + + + +
+
+ + + + + +
+
+
+
+
{$_LANG['Graphs']['CPU']}
+
+
+
+

{$_LANG['Graphs']['Loading']}

+
+
+
+
+ +
+
+
+
{$_LANG['Graphs']['RAM']}
+
+
+
+

{$_LANG['Graphs']['Loading']}

+
+
+
+
+ +
+
+
+
{$_LANG['Graphs']['Network']}
+
+
+
+

{$_LANG['Graphs']['Loading']}

+
+
+
+
+ +
+
+
+
{$_LANG['Graphs']['Disk']}
+
+
+
+

{$_LANG['Graphs']['Loading']}

+
+
+
+
+
+
+ +
+
+ + {$_LANG['Navbar']['Backups']} +
+ +
{$_LANG['Backups']['Description']}
+ +
+ + + + + + + + + + + + + + + +
{$_LANG['Backups']['Date']}{$_LANG['Backups']['Size']}{$_LANG['Backups']['Type']}{$_LANG['Backups']['Status']}{$_LANG['Backups']['Actions']}
Loading backup data...
+
+ + + +
+ {$_LANG['Backups']['Warning']|unescape:'html'} +
+
+ +
+
+ {$_LANG['General']['Note']}: {$_LANG['Settings']['Firewall']['Description']} +
+ + +
+
+
{$_LANG['Settings']['Firewall']['AddNewRule']}
+
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+
+ +
+
+
+ + +
+
+
{$_LANG['Settings']['Firewall']['CurrentRules']}
+
+
+
+ + + + + + + + + + + + + + + + +
{$_LANG['Settings']['Firewall']['Action']}{$_LANG['Settings']['Firewall']['Protocol']}{$_LANG['Settings']['Firewall']['Port']}{$_LANG['Settings']['Firewall']['Source']}{$_LANG['Settings']['Firewall']['Note']}{$_LANG['Settings']['Firewall']['Actions']}
+ {$_LANG['LoadingFirewallRules']} +
+
+
+
+ + +
+ {$_LANG['General']['Note']}: {$_LANG['Settings']['Firewall']['Warning']} +
+
+ +
+
+ +
+
+ +
+
+
+
+ + {$_LANG['Settings']['Hostname']['Title']} +
+ +
+ {$_LANG['Settings']['Hostname']['Description']} +
+ +
+
+
+ + +
+
+
+ + +
+ +
+
+ + {$_LANG['Settings']['ISO']['Title']} +
+ +
+ {$_LANG['Settings']['ISO']['Description']} +
+ +
+
+
+ + +
+
+
+ + + + {if $serverInfo['iso'] !== ''} + + {/if} +
+ +
+
+ + {$_LANG['Settings']['Password']['Title']} +
+ +
+ {$_LANG['Settings']['Password']['Description']} +
+ +
+
+
+ + +
+ + +
+
+
+
+ + +
+ +
+
+ + {$_LANG['Settings']['Reinstall']['Title']} +
+ +
+ {$_LANG['Settings']['Reinstall']['Description']} +
+ +
+ + +
+ {foreach from=$operatingSystems key=$group item=$operatingSystemsGroup} +
+ +
+ {/foreach} +
+ + + + + + +
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/template/css/app.css b/modules/servers/ArkhostVPSAG/template/css/app.css new file mode 100644 index 0000000..a27434c --- /dev/null +++ b/modules/servers/ArkhostVPSAG/template/css/app.css @@ -0,0 +1,1040 @@ +html, body { + font-family: sans-serif; + font-size: 14px; + padding: 5px 10px; +} + +.badge { + padding: 0.50rem 1.00rem; + white-space: normal !important; +} + +span.badge { + margin-bottom: 8px; +} + +.fade:not(.show) { + display: none; +} + +#loading { + position: fixed; + color: #65686a; + display: none; + z-index: 1000000; +} + +#loading-spinner { + position: fixed; + overflow: visible; + margin: auto; + top: 0; + left: 0; + bottom: 0; + right: 0; +} + +#loading:before { + content: ''; + display: block; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.3); +} + +a { + cursor: pointer; +} + +img { + border-style: none; + /* margin-bottom: 10px; */ + vertical-align: middle; +} + +img .flag { + border: 1px solid #ddd; +} + +.information { + left: 0; + right: 0; + bottom: 0; + color: #343a40; + position: absolute; +} + +.form-label { + color: #868888; + margin-bottom: 0px; + word-break: break-all; +} + +.border { + display: flex; + min-height: 125px; + position: relative; + align-items: center; + justify-content: center; +} + +.mb-3, +.my-3 { + margin-bottom: 1rem!important; +} + +.without-mb { + margin-bottom: 0rem!important; +} + +.p-2 { + padding: .5rem!important; +} + +i.fa-play.start { + color: #06d79c; + font-size: 25px; +} + +i.fa-stop.stop { + color: #656373; + font-size: 25px; +} + +i.fa-sync.reboot { + color: #398bf7; + font-size: 25px; +} + +.vnc { + height: 25px; +} + +.dashboard-title { + color: #3d3d3d; + font-size: 22px; +} + +.dashboard-value { + color: #586271 !important; +} + +.usage-details { + border: 1px solid #e7e4e4; + transition: all ease-in .2s; +} + +.usage-details:hover { + border: 1px solid transparent; + box-shadow: 1px 1px 8px 6px #e5e3e3bf; +} + +.overview-label { + color: #99abb4; +} + +.progress.disk-bar { + height: 14px; + margin-top: 25px; + margin-bottom: 20px; + border-radius: 6px; + -webkit-box-shadow: none; + box-shadow: none; +} + +.used_disk_percent { + color: #1e88e5; + font-size: 20px; +} + +.dashboard-tab .nav-tabs { + border-bottom: 1px solid #dfd8d8; + margin: 0; +} + +.dashboard-tab .nav-tabs .nav-item { + border-bottom: 1px solid #dfd8d8; +} + +.dashboard-tab .nav-tabs li a { + position: relative; + padding: 5px; + margin-right: 10px; + color: #374045 !important; + border: none; + border-radius: 0; + background: transparent; + transition: all 0.3s ease 0s; + z-index: 2; +} + +.dashboard-tab .nav-tabs li a:before { + content: ""; + width: 100%; + height: 4px; + border-radius: 2px; + position: absolute; + bottom: 0; + left: 0; +} + +.dashboard-tab .nav-tabs li a:after { + content: ""; + width: 0; + height: 4px; + background: linear-gradient(to right, #396afc, #2948ff); + border-bottom: 1px solid #727cb6; + border-radius: 2px; + position: absolute; + bottom: -2px; + left: 0; + transition: all .4s ease 0s; + z-index: 1; +} + +.dashboard-tab .nav-tabs li a.active:after { + width: 100%; + opacity: 1; +} + +.vertical-tabs .nav-link { + color: #515a68; + padding: 7px 5px; + margin-bottom: 10px; + transition: all ease-in 0.2s; + text-align: left!important; +} + +.vertical-tabs .nav-link.active { + border-radius: 0px; + color: #2948ff; +} + +.v-tabs-container { + border-right: 1px solid #dfd8d8; +} + +.nav-pills .nav-link.active { + background-color: unset; +} + +.custom-control-input:checked~.custom-control-label::before { + color: #fff; + border-color: #007bff; + background-color: #007bff; +} + +.info-text { + color: #398bf7; + cursor: pointer; +} + +#graphs-tab .nav-link, +#sub-tasks-and-logs .nav-link { + color: #576170; + transition: all 0.4s linear; +} + +#graphs-tab .nav-link.active, +#sub-tasks-and-logs .nav-link.active { + border-radius: 0px; + color: #ffffff; + background: linear-gradient(to right, #396afc, #2948ff); +} + +.prev-mnth.green_but, +.next-mnth.green_but { + padding: 4px 10px; +} + +.graphs img { + width: 100%; +} + +.submit-btn { + background-color: #398bf7; + border: none; + border-radius: 4px; + color: #ffffff; + font-weight: 500; + padding: 7px 12px; + transition: 0.2s ease-in; +} + +.cancel-btn { + background-color: #5a6268; + border: none; + border-radius: 4px; + color: #ffffff; + font-weight: 500; + padding: 7px 12px; + transition: 0.2s ease-in; +} + +.danger-btn { + background-color: #dc3545; + border: none; + border-radius: 4px; + color: #ffffff; + font-weight: 500; + padding: 7px 12px; + transition: 0.2s ease-in; +} + +.submit-btn:hover { + color: #ffffff !important; + box-shadow: 0 14px 26px -12px #1769ff6b, 0 4px 23px 0 #0000001f, 0 8px 10px -5px #1769ff33; +} + +.cancel-btn:hover { + color: #ffffff !important; + box-shadow: 0 14px 26px -12px #000000, 0 4px 23px 0 #0000001f, 0 8px 10px -5px #07183533; +} + +.modal-title { + font-weight: 400; + color: #455a64; +} + +.modal-title i.success { + font-size: 40px; + color: #06d79c; + vertical-align: middle; +} + +.modal-title i.warning { + font-size: 40px; + color: orange; + vertical-align: middle; +} + +.modal-title i.error { + font-size: 40px; + color: #ef5350; + vertical-align: middle; +} + +.modal-body { + color: #868888; + font-weight: 500; + line-height: 30px; + margin-bottom: 0px; +} + +.modal-body p { + margin-bottom: 0px; +} + +.link-btn { + background-color: #398bf7; + border: none; + border-radius: 4px; + text-decoration: none !important; + color: #ffffff !important; + font-size: 14px; + padding: 7px 12px; + transition: 0.2s ease-in; +} + +.link-btn:hover { + text-decoration: none; + color: #ffffff; + box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2); +} + +.v-tab-heading { + color: #515557; + font-size: 18px; +} + +.distro_img { + width: 64px; + height: 64px; +} + +.distro_name.media-heading { + color: #3d3d3d; + font-size: 22px; +} + +.float-left { + float: left!important; +} + +.media { + display: -ms-flexbox; + display: flex; + -ms-flex-align: start; + align-items: flex-start; +} + +.version { + color: #586271; + font-size: 12px; +} + +.info-icon { + background-color: #007bff; + color: #fff; + padding: 4px 12px; + border: none; + border-radius: 4px; +} + +.info-icon:hover, +.info-icon:focus { + border: none; + box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2); +} + +.info-icon i { + font-size: 12px; +} + +.os_badge { + border: 1px solid #ccc; + cursor: pointer; + transition: height 0.5s; + border-radius: 3px; + position: relative; +} + +#os_list .dropdown-menu { + max-height: 200px; + overflow-y: auto; +} + +.os_badge_list a { + color: #576170; + text-decoration: none; + outline: none; + display: block; + padding: 8px; + background-color: #fff; +} + +.os_badge_list a:hover { + color: #2f3235; + background-color: #f9f6f6; +} + +.os_badge_list .SelectedOS { + color: #ffffff; + background-color: #2196F3; +} + +.os_badge.selected .version, +.os_badge.selected .distro_name.media-heading, +.os_badge.selected i { + color: #ffffff; +} + +.os_badge.selected { + color: #fff; + background-color: #06d79c; +} + +.os_badge i { + position: absolute; + top: 26px; + right: 16px; + color: #aaa; +} + +.os_badge .media-left { + padding: 8px; +} + +.os_badge .media-body { + padding: 8px; + vertical-align: middle; + text-align: left!important; +} + +.os_badge .version { + color: #888; +} + +.os_badge.expanded { + position: relative; + z-index: 999; +} + +.os_badge .dropdown-toggle::after { + content: none; +} + +.tab-content>.tab-pane { + display: none; +} + +.tab-content>.active { + display: block; +} + +.head { + margin-bottom: 10px; +} + +.head>img { + width: 32px; +} + +.restore-icon { + font-size: 17px; +} + +.create { + color: #06d79c; +} + +.delete { + color: #ff0000; +} + +.table.dataTable.no-footer { + border-bottom: 1px solid #5d5b63 !important; +} + +table.tablesorter { + box-shadow: 0 2px 12px -3px rgba(0, 0, 0, 0.5); +} + +table.dataTable { + clear: both; + margin-top: 6px !important; + margin-bottom: 6px !important; + max-width: none !important; + border-collapse: separate !important; + border-spacing: 0; +} + +#firewallTable th, +#backupTable th { + color: #ffffff; + background-color: #36304a !important; + border: unset !important; + font-weight: unset !important; + position: sticky !important; + top: -1px; + z-index: 99; +} + +.fa-1x { + font-size: 20px !important; +} + +.grey-txt { + color: #666; +} + +.showPassword { + text-decoration: none; +} + +.scrtabs-tab-scroll-arrow { + top: calc(50% - 10px); + color: #396afc; + height: 20px; + border: none; + position: relative; + padding-top: 0px; + padding-left: 0px; +} + +select, +textarea, +input[type=text], +input[type=textbox], +input[type=password] { + background: #fff; + font-size: 12px; + color: #455a64; + border: 1px #CCCCCC solid; + transition: background 0.3s linear; + -webkit-transition: background 0.3s linear; + outline: none; +} + +select, +textarea, +input[type=text], +input[type=number], +input[type=textbox], +input[type=password] { + box-shadow: 0 2px 2px 0 #a9a9a924, 0 3px 1px -2px #a9a9a933, 0 1px 5px 0 #a9a9a91f; +} + +.form-control { + height: 35px; + font-size: 14px !important; + min-height: 40px; + margin-bottom: 8px; + color: #67757c; + display: inline-block; + border-radius: 4px; +} + +.input-group-text { + height: 35px; + font-size: 14px !important; + min-height: 40px; + margin-bottom: 8px; +} + +.ml-auto, +.mx-auto { + margin-left: auto !important; + margin-right: auto !important; +} + +.mr-2, +.mx-2 { + margin-right: .5rem!important; +} + +@media all and (max-width: 576px) { + .left-side-tabs { + border-bottom: 1px solid #dfd8d8; + } + + .vertical-tabs .nav-link { + padding: 7px 10px; + } + + .left-side-tabs .nav-link.active { + color: #ffffff; + background:linear-gradient(to right, #396afc, #2948ff); + } + + .vertical-tab-content form select, + .vertical-tab-content form input[type=text], + .vertical-tab-content form input[type=textbox], + .vertical-tab-content form input[type=password] { + width:100%; + } +} + +/* ============================================ + Enhanced Modern Styling + ============================================ */ + +/* Card Styling */ +.card { + border-radius: 12px !important; + border: 1px solid #e3e6f0 !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + transition: all 0.3s ease; +} + +.card:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +} + +.card-header { + border-radius: 12px 12px 0 0 !important; + background-color: #f8f9fa !important; + border-bottom: 1px solid #e3e6f0 !important; + padding: 12px 20px !important; +} + +.card-body { + padding: 20px !important; +} + +/* Enhanced Button Styles */ +.btn { + border-radius: 12px !important; + font-weight: 500; + transition: all 0.3s ease; + padding: 10px 20px; +} + +.btn-success { + background: linear-gradient(135deg, #28a745 0%, #20c997 100%) !important; + border: none !important; + box-shadow: 0 2px 8px rgba(40, 167, 69, 0.3); +} + +.btn-success:hover { + background: linear-gradient(135deg, #218838 0%, #1aa179 100%) !important; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(40, 167, 69, 0.4); +} + +.btn-primary { + background: linear-gradient(135deg, #3c7fb4 0%, #2d5a87 100%) !important; + border: none !important; + box-shadow: 0 2px 8px rgba(60, 127, 180, 0.3); +} + +.btn-primary:hover { + background: linear-gradient(135deg, #2d5a87 0%, #1e3a57 100%) !important; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(60, 127, 180, 0.4); +} + +.btn-danger { + background: linear-gradient(135deg, #dc3545 0%, #c82333 100%) !important; + border: none !important; + box-shadow: 0 2px 8px rgba(220, 53, 69, 0.3); +} + +.btn-danger:hover { + background: linear-gradient(135deg, #c82333 0%, #bd2130 100%) !important; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(220, 53, 69, 0.4); +} + +.btn-lg { + padding: 12px 32px !important; + font-size: 16px !important; +} + +/* Improved submit-btn to match Hetzner style */ +.submit-btn { + background: linear-gradient(135deg, #3c7fb4 0%, #2d5a87 100%) !important; + border: none !important; + border-radius: 12px !important; + color: #ffffff !important; + font-weight: 600 !important; + padding: 10px 20px !important; + transition: all 0.3s ease !important; + box-shadow: 0 2px 8px rgba(60, 127, 180, 0.3); +} + +.submit-btn:hover { + background: linear-gradient(135deg, #2d5a87 0%, #1e3a57 100%) !important; + color: #ffffff !important; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(60, 127, 180, 0.4) !important; +} + +/* Table Styling */ +.table { + border-collapse: separate; + border-spacing: 0; +} + +.table thead th { + border-bottom: 2px solid #dee2e6 !important; + color: #495057; + font-weight: 600; + text-transform: uppercase; + font-size: 0.85rem; + letter-spacing: 0.5px; +} + +.table-hover tbody tr { + transition: all 0.2s ease; +} + +.table-hover tbody tr:hover { + background-color: #f8f9fa; + transform: scale(1.01); +} + +.thead-light th { + background-color: #f8f9fa !important; +} + +/* Form Control Improvements */ +.form-control { + border-radius: 8px !important; + border: 1px solid #ced4da !important; + transition: all 0.2s ease; + padding: 8px 12px; +} + +.form-control:focus { + border-color: #3c7fb4 !important; + box-shadow: 0 0 0 0.2rem rgba(60, 127, 180, 0.25) !important; +} + +/* Alert Styling */ +.alert { + border-radius: 12px !important; + border: none !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); +} + +.alert-info { + background: linear-gradient(135deg, #e7f3ff 0%, #d4e9ff 100%); + color: #004085; +} + +.alert-warning { + background: linear-gradient(135deg, #fff3cd 0%, #ffe5a1 100%); + color: #856404; +} + +.alert-success { + background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%); + color: #155724; +} + +/* Firewall Specific Styles */ +#firewall .card.border-primary { + border: 2px solid #3c7fb4 !important; + box-shadow: 0 4px 16px rgba(60, 127, 180, 0.15); +} + +#firewall .card-header.bg-light { + background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%) !important; +} + +#firewall .card-header h6 { + margin: 0; + color: #2c3e50; + font-weight: 600; +} + +/* Delete Icon Styling */ +.fa-trash { + transition: all 0.2s ease; + cursor: pointer; +} + +.fa-trash:hover { + transform: scale(1.2); + color: #dc3545 !important; +} + +/* Loading Spinner */ +.fa-spinner { + animation: spin 1s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Smooth transitions for tab content */ +.tab-pane { + animation: fadeIn 0.3s ease-in; +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Nav tabs enhancement */ +.nav-tabs .nav-link { + border-radius: 12px 12px 0 0 !important; + transition: all 0.2s ease; +} + +.nav-tabs .nav-link:hover { + background-color: #f8f9fa; +} + +.nav-tabs .nav-link.active { + background-color: #e9ecef !important; + font-weight: 600; +} + +/* Icon improvements */ +.fa, .fas, .far { + vertical-align: middle; +} + +/* Small label styling */ +label.small { + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 6px; +} + +/* Text center improvements */ +.text-center { + text-align: center; +} + +/* Resource Box Styling */ +.resource-box { + padding: 20px 10px; + transition: all 0.3s ease; +} + +.resource-box:hover { + transform: translateY(-5px); +} + +.resource-box h3 { + color: #2c3e50; + font-weight: 600; +} + +.resource-box .text-primary { + color: #3c7fb4 !important; +} + +.resource-box .text-success { + color: #28a745 !important; +} + +.resource-box .text-warning { + color: #ffc107 !important; +} + +.resource-box .text-info { + color: #17a2b8 !important; +} + +/* Card Header Enhancement */ +.card-header.bg-primary { + background: linear-gradient(135deg, #3c7fb4 0%, #2d5a87 100%) !important; +} + +.card-header h5 { + margin: 0; + font-weight: 600; +} + +/* Table Enhancements */ +.table-borderless td { + padding: 8px 12px; + vertical-align: middle; +} + +.table-borderless code { + background-color: #f8f9fa; + padding: 4px 8px; + border-radius: 4px; + font-size: 12px; + color: #e83e8c; +} + +/* Usage Details Box Enhancement */ +.usage-details { + border-radius: 12px !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + transition: all 0.3s ease; +} + +.usage-details:hover { + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12); + transform: translateY(-2px); +} + +/* VPS Control Button Styles - Hetzner Style */ +.vps-control-btn { + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + padding: 12px 24px !important; + border-radius: 25px !important; + margin: 8px 4px !important; + transition: all 0.3s ease !important; + text-decoration: none !important; + color: white !important; + font-size: 0.95rem !important; + font-weight: 600 !important; + min-height: 48px !important; + box-shadow: 0 3px 8px rgba(0,0,0,0.15) !important; + border: none !important; + position: relative !important; + overflow: hidden !important; +} + +.vps-control-btn:hover { + transform: translateY(-3px) !important; + box-shadow: 0 6px 16px rgba(0,0,0,0.2) !important; + text-decoration: none !important; + color: white !important; +} + +.vps-control-btn:active { + transform: translateY(-1px) !important; + box-shadow: 0 3px 8px rgba(0,0,0,0.15) !important; +} + +.vps-control-btn.start-btn { + background: linear-gradient(45deg, #28a745, #34ce57) !important; + color: white !important; +} + +.vps-control-btn.start-btn:hover { + background: linear-gradient(45deg, #218838, #28a745) !important; + color: white !important; +} + +.vps-control-btn.stop-btn { + background: linear-gradient(45deg, #dc3545, #ff4757) !important; + color: white !important; +} + +.vps-control-btn.stop-btn:hover { + background: linear-gradient(45deg, #c82333, #dc3545) !important; + color: white !important; +} + +.vps-control-btn.restart-btn { + background: linear-gradient(45deg, #fd7e14, #ff9f43) !important; + color: white !important; +} + +.vps-control-btn.restart-btn:hover { + background: linear-gradient(45deg, #e65100, #fd7e14) !important; + color: white !important; +} + +.vps-control-btn.vnc-btn { + background: linear-gradient(45deg, #6f42c1, #8854d0) !important; + color: white !important; +} + +.vps-control-btn.vnc-btn:hover { + background: linear-gradient(45deg, #5a32a3, #6f42c1) !important; + color: white !important; +} + +.vps-control-btn.vnc-btn img { + width: 20px !important; + height: 20px !important; + margin-right: 8px !important; + filter: brightness(0) invert(1); +} + +.vps-control-btn i { + margin-right: 8px !important; + font-size: 1.1rem !important; +} + +/* Mobile Responsive - Stack VPS Control Buttons Vertically */ +@media (max-width: 767px) { + .vps-control-btn { + display: block !important; + width: 100% !important; + margin: 8px 0 !important; + text-align: center !important; + } +} + +/* Responsive padding */ +@media (max-width: 768px) { + .card-body { + padding: 15px !important; + } + + .btn-lg { + padding: 10px 24px !important; + font-size: 14px !important; + } + + .resource-box { + padding: 15px 5px; + } +} \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/template/css/app.min.css b/modules/servers/ArkhostVPSAG/template/css/app.min.css new file mode 100644 index 0000000..a27434c --- /dev/null +++ b/modules/servers/ArkhostVPSAG/template/css/app.min.css @@ -0,0 +1,1040 @@ +html, body { + font-family: sans-serif; + font-size: 14px; + padding: 5px 10px; +} + +.badge { + padding: 0.50rem 1.00rem; + white-space: normal !important; +} + +span.badge { + margin-bottom: 8px; +} + +.fade:not(.show) { + display: none; +} + +#loading { + position: fixed; + color: #65686a; + display: none; + z-index: 1000000; +} + +#loading-spinner { + position: fixed; + overflow: visible; + margin: auto; + top: 0; + left: 0; + bottom: 0; + right: 0; +} + +#loading:before { + content: ''; + display: block; + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; + background-color: rgba(0, 0, 0, 0.3); +} + +a { + cursor: pointer; +} + +img { + border-style: none; + /* margin-bottom: 10px; */ + vertical-align: middle; +} + +img .flag { + border: 1px solid #ddd; +} + +.information { + left: 0; + right: 0; + bottom: 0; + color: #343a40; + position: absolute; +} + +.form-label { + color: #868888; + margin-bottom: 0px; + word-break: break-all; +} + +.border { + display: flex; + min-height: 125px; + position: relative; + align-items: center; + justify-content: center; +} + +.mb-3, +.my-3 { + margin-bottom: 1rem!important; +} + +.without-mb { + margin-bottom: 0rem!important; +} + +.p-2 { + padding: .5rem!important; +} + +i.fa-play.start { + color: #06d79c; + font-size: 25px; +} + +i.fa-stop.stop { + color: #656373; + font-size: 25px; +} + +i.fa-sync.reboot { + color: #398bf7; + font-size: 25px; +} + +.vnc { + height: 25px; +} + +.dashboard-title { + color: #3d3d3d; + font-size: 22px; +} + +.dashboard-value { + color: #586271 !important; +} + +.usage-details { + border: 1px solid #e7e4e4; + transition: all ease-in .2s; +} + +.usage-details:hover { + border: 1px solid transparent; + box-shadow: 1px 1px 8px 6px #e5e3e3bf; +} + +.overview-label { + color: #99abb4; +} + +.progress.disk-bar { + height: 14px; + margin-top: 25px; + margin-bottom: 20px; + border-radius: 6px; + -webkit-box-shadow: none; + box-shadow: none; +} + +.used_disk_percent { + color: #1e88e5; + font-size: 20px; +} + +.dashboard-tab .nav-tabs { + border-bottom: 1px solid #dfd8d8; + margin: 0; +} + +.dashboard-tab .nav-tabs .nav-item { + border-bottom: 1px solid #dfd8d8; +} + +.dashboard-tab .nav-tabs li a { + position: relative; + padding: 5px; + margin-right: 10px; + color: #374045 !important; + border: none; + border-radius: 0; + background: transparent; + transition: all 0.3s ease 0s; + z-index: 2; +} + +.dashboard-tab .nav-tabs li a:before { + content: ""; + width: 100%; + height: 4px; + border-radius: 2px; + position: absolute; + bottom: 0; + left: 0; +} + +.dashboard-tab .nav-tabs li a:after { + content: ""; + width: 0; + height: 4px; + background: linear-gradient(to right, #396afc, #2948ff); + border-bottom: 1px solid #727cb6; + border-radius: 2px; + position: absolute; + bottom: -2px; + left: 0; + transition: all .4s ease 0s; + z-index: 1; +} + +.dashboard-tab .nav-tabs li a.active:after { + width: 100%; + opacity: 1; +} + +.vertical-tabs .nav-link { + color: #515a68; + padding: 7px 5px; + margin-bottom: 10px; + transition: all ease-in 0.2s; + text-align: left!important; +} + +.vertical-tabs .nav-link.active { + border-radius: 0px; + color: #2948ff; +} + +.v-tabs-container { + border-right: 1px solid #dfd8d8; +} + +.nav-pills .nav-link.active { + background-color: unset; +} + +.custom-control-input:checked~.custom-control-label::before { + color: #fff; + border-color: #007bff; + background-color: #007bff; +} + +.info-text { + color: #398bf7; + cursor: pointer; +} + +#graphs-tab .nav-link, +#sub-tasks-and-logs .nav-link { + color: #576170; + transition: all 0.4s linear; +} + +#graphs-tab .nav-link.active, +#sub-tasks-and-logs .nav-link.active { + border-radius: 0px; + color: #ffffff; + background: linear-gradient(to right, #396afc, #2948ff); +} + +.prev-mnth.green_but, +.next-mnth.green_but { + padding: 4px 10px; +} + +.graphs img { + width: 100%; +} + +.submit-btn { + background-color: #398bf7; + border: none; + border-radius: 4px; + color: #ffffff; + font-weight: 500; + padding: 7px 12px; + transition: 0.2s ease-in; +} + +.cancel-btn { + background-color: #5a6268; + border: none; + border-radius: 4px; + color: #ffffff; + font-weight: 500; + padding: 7px 12px; + transition: 0.2s ease-in; +} + +.danger-btn { + background-color: #dc3545; + border: none; + border-radius: 4px; + color: #ffffff; + font-weight: 500; + padding: 7px 12px; + transition: 0.2s ease-in; +} + +.submit-btn:hover { + color: #ffffff !important; + box-shadow: 0 14px 26px -12px #1769ff6b, 0 4px 23px 0 #0000001f, 0 8px 10px -5px #1769ff33; +} + +.cancel-btn:hover { + color: #ffffff !important; + box-shadow: 0 14px 26px -12px #000000, 0 4px 23px 0 #0000001f, 0 8px 10px -5px #07183533; +} + +.modal-title { + font-weight: 400; + color: #455a64; +} + +.modal-title i.success { + font-size: 40px; + color: #06d79c; + vertical-align: middle; +} + +.modal-title i.warning { + font-size: 40px; + color: orange; + vertical-align: middle; +} + +.modal-title i.error { + font-size: 40px; + color: #ef5350; + vertical-align: middle; +} + +.modal-body { + color: #868888; + font-weight: 500; + line-height: 30px; + margin-bottom: 0px; +} + +.modal-body p { + margin-bottom: 0px; +} + +.link-btn { + background-color: #398bf7; + border: none; + border-radius: 4px; + text-decoration: none !important; + color: #ffffff !important; + font-size: 14px; + padding: 7px 12px; + transition: 0.2s ease-in; +} + +.link-btn:hover { + text-decoration: none; + color: #ffffff; + box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2); +} + +.v-tab-heading { + color: #515557; + font-size: 18px; +} + +.distro_img { + width: 64px; + height: 64px; +} + +.distro_name.media-heading { + color: #3d3d3d; + font-size: 22px; +} + +.float-left { + float: left!important; +} + +.media { + display: -ms-flexbox; + display: flex; + -ms-flex-align: start; + align-items: flex-start; +} + +.version { + color: #586271; + font-size: 12px; +} + +.info-icon { + background-color: #007bff; + color: #fff; + padding: 4px 12px; + border: none; + border-radius: 4px; +} + +.info-icon:hover, +.info-icon:focus { + border: none; + box-shadow: 0 14px 26px -12px rgba(23, 105, 255, 0.42), 0 4px 23px 0 rgba(0, 0, 0, 0.12), 0 8px 10px -5px rgba(23, 105, 255, 0.2); +} + +.info-icon i { + font-size: 12px; +} + +.os_badge { + border: 1px solid #ccc; + cursor: pointer; + transition: height 0.5s; + border-radius: 3px; + position: relative; +} + +#os_list .dropdown-menu { + max-height: 200px; + overflow-y: auto; +} + +.os_badge_list a { + color: #576170; + text-decoration: none; + outline: none; + display: block; + padding: 8px; + background-color: #fff; +} + +.os_badge_list a:hover { + color: #2f3235; + background-color: #f9f6f6; +} + +.os_badge_list .SelectedOS { + color: #ffffff; + background-color: #2196F3; +} + +.os_badge.selected .version, +.os_badge.selected .distro_name.media-heading, +.os_badge.selected i { + color: #ffffff; +} + +.os_badge.selected { + color: #fff; + background-color: #06d79c; +} + +.os_badge i { + position: absolute; + top: 26px; + right: 16px; + color: #aaa; +} + +.os_badge .media-left { + padding: 8px; +} + +.os_badge .media-body { + padding: 8px; + vertical-align: middle; + text-align: left!important; +} + +.os_badge .version { + color: #888; +} + +.os_badge.expanded { + position: relative; + z-index: 999; +} + +.os_badge .dropdown-toggle::after { + content: none; +} + +.tab-content>.tab-pane { + display: none; +} + +.tab-content>.active { + display: block; +} + +.head { + margin-bottom: 10px; +} + +.head>img { + width: 32px; +} + +.restore-icon { + font-size: 17px; +} + +.create { + color: #06d79c; +} + +.delete { + color: #ff0000; +} + +.table.dataTable.no-footer { + border-bottom: 1px solid #5d5b63 !important; +} + +table.tablesorter { + box-shadow: 0 2px 12px -3px rgba(0, 0, 0, 0.5); +} + +table.dataTable { + clear: both; + margin-top: 6px !important; + margin-bottom: 6px !important; + max-width: none !important; + border-collapse: separate !important; + border-spacing: 0; +} + +#firewallTable th, +#backupTable th { + color: #ffffff; + background-color: #36304a !important; + border: unset !important; + font-weight: unset !important; + position: sticky !important; + top: -1px; + z-index: 99; +} + +.fa-1x { + font-size: 20px !important; +} + +.grey-txt { + color: #666; +} + +.showPassword { + text-decoration: none; +} + +.scrtabs-tab-scroll-arrow { + top: calc(50% - 10px); + color: #396afc; + height: 20px; + border: none; + position: relative; + padding-top: 0px; + padding-left: 0px; +} + +select, +textarea, +input[type=text], +input[type=textbox], +input[type=password] { + background: #fff; + font-size: 12px; + color: #455a64; + border: 1px #CCCCCC solid; + transition: background 0.3s linear; + -webkit-transition: background 0.3s linear; + outline: none; +} + +select, +textarea, +input[type=text], +input[type=number], +input[type=textbox], +input[type=password] { + box-shadow: 0 2px 2px 0 #a9a9a924, 0 3px 1px -2px #a9a9a933, 0 1px 5px 0 #a9a9a91f; +} + +.form-control { + height: 35px; + font-size: 14px !important; + min-height: 40px; + margin-bottom: 8px; + color: #67757c; + display: inline-block; + border-radius: 4px; +} + +.input-group-text { + height: 35px; + font-size: 14px !important; + min-height: 40px; + margin-bottom: 8px; +} + +.ml-auto, +.mx-auto { + margin-left: auto !important; + margin-right: auto !important; +} + +.mr-2, +.mx-2 { + margin-right: .5rem!important; +} + +@media all and (max-width: 576px) { + .left-side-tabs { + border-bottom: 1px solid #dfd8d8; + } + + .vertical-tabs .nav-link { + padding: 7px 10px; + } + + .left-side-tabs .nav-link.active { + color: #ffffff; + background:linear-gradient(to right, #396afc, #2948ff); + } + + .vertical-tab-content form select, + .vertical-tab-content form input[type=text], + .vertical-tab-content form input[type=textbox], + .vertical-tab-content form input[type=password] { + width:100%; + } +} + +/* ============================================ + Enhanced Modern Styling + ============================================ */ + +/* Card Styling */ +.card { + border-radius: 12px !important; + border: 1px solid #e3e6f0 !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.05); + transition: all 0.3s ease; +} + +.card:hover { + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); +} + +.card-header { + border-radius: 12px 12px 0 0 !important; + background-color: #f8f9fa !important; + border-bottom: 1px solid #e3e6f0 !important; + padding: 12px 20px !important; +} + +.card-body { + padding: 20px !important; +} + +/* Enhanced Button Styles */ +.btn { + border-radius: 12px !important; + font-weight: 500; + transition: all 0.3s ease; + padding: 10px 20px; +} + +.btn-success { + background: linear-gradient(135deg, #28a745 0%, #20c997 100%) !important; + border: none !important; + box-shadow: 0 2px 8px rgba(40, 167, 69, 0.3); +} + +.btn-success:hover { + background: linear-gradient(135deg, #218838 0%, #1aa179 100%) !important; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(40, 167, 69, 0.4); +} + +.btn-primary { + background: linear-gradient(135deg, #3c7fb4 0%, #2d5a87 100%) !important; + border: none !important; + box-shadow: 0 2px 8px rgba(60, 127, 180, 0.3); +} + +.btn-primary:hover { + background: linear-gradient(135deg, #2d5a87 0%, #1e3a57 100%) !important; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(60, 127, 180, 0.4); +} + +.btn-danger { + background: linear-gradient(135deg, #dc3545 0%, #c82333 100%) !important; + border: none !important; + box-shadow: 0 2px 8px rgba(220, 53, 69, 0.3); +} + +.btn-danger:hover { + background: linear-gradient(135deg, #c82333 0%, #bd2130 100%) !important; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(220, 53, 69, 0.4); +} + +.btn-lg { + padding: 12px 32px !important; + font-size: 16px !important; +} + +/* Improved submit-btn to match Hetzner style */ +.submit-btn { + background: linear-gradient(135deg, #3c7fb4 0%, #2d5a87 100%) !important; + border: none !important; + border-radius: 12px !important; + color: #ffffff !important; + font-weight: 600 !important; + padding: 10px 20px !important; + transition: all 0.3s ease !important; + box-shadow: 0 2px 8px rgba(60, 127, 180, 0.3); +} + +.submit-btn:hover { + background: linear-gradient(135deg, #2d5a87 0%, #1e3a57 100%) !important; + color: #ffffff !important; + transform: translateY(-2px); + box-shadow: 0 4px 12px rgba(60, 127, 180, 0.4) !important; +} + +/* Table Styling */ +.table { + border-collapse: separate; + border-spacing: 0; +} + +.table thead th { + border-bottom: 2px solid #dee2e6 !important; + color: #495057; + font-weight: 600; + text-transform: uppercase; + font-size: 0.85rem; + letter-spacing: 0.5px; +} + +.table-hover tbody tr { + transition: all 0.2s ease; +} + +.table-hover tbody tr:hover { + background-color: #f8f9fa; + transform: scale(1.01); +} + +.thead-light th { + background-color: #f8f9fa !important; +} + +/* Form Control Improvements */ +.form-control { + border-radius: 8px !important; + border: 1px solid #ced4da !important; + transition: all 0.2s ease; + padding: 8px 12px; +} + +.form-control:focus { + border-color: #3c7fb4 !important; + box-shadow: 0 0 0 0.2rem rgba(60, 127, 180, 0.25) !important; +} + +/* Alert Styling */ +.alert { + border-radius: 12px !important; + border: none !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); +} + +.alert-info { + background: linear-gradient(135deg, #e7f3ff 0%, #d4e9ff 100%); + color: #004085; +} + +.alert-warning { + background: linear-gradient(135deg, #fff3cd 0%, #ffe5a1 100%); + color: #856404; +} + +.alert-success { + background: linear-gradient(135deg, #d4edda 0%, #c3e6cb 100%); + color: #155724; +} + +/* Firewall Specific Styles */ +#firewall .card.border-primary { + border: 2px solid #3c7fb4 !important; + box-shadow: 0 4px 16px rgba(60, 127, 180, 0.15); +} + +#firewall .card-header.bg-light { + background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%) !important; +} + +#firewall .card-header h6 { + margin: 0; + color: #2c3e50; + font-weight: 600; +} + +/* Delete Icon Styling */ +.fa-trash { + transition: all 0.2s ease; + cursor: pointer; +} + +.fa-trash:hover { + transform: scale(1.2); + color: #dc3545 !important; +} + +/* Loading Spinner */ +.fa-spinner { + animation: spin 1s linear infinite; +} + +@keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } +} + +/* Smooth transitions for tab content */ +.tab-pane { + animation: fadeIn 0.3s ease-in; +} + +@keyframes fadeIn { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +/* Nav tabs enhancement */ +.nav-tabs .nav-link { + border-radius: 12px 12px 0 0 !important; + transition: all 0.2s ease; +} + +.nav-tabs .nav-link:hover { + background-color: #f8f9fa; +} + +.nav-tabs .nav-link.active { + background-color: #e9ecef !important; + font-weight: 600; +} + +/* Icon improvements */ +.fa, .fas, .far { + vertical-align: middle; +} + +/* Small label styling */ +label.small { + font-weight: 600; + text-transform: uppercase; + letter-spacing: 0.5px; + margin-bottom: 6px; +} + +/* Text center improvements */ +.text-center { + text-align: center; +} + +/* Resource Box Styling */ +.resource-box { + padding: 20px 10px; + transition: all 0.3s ease; +} + +.resource-box:hover { + transform: translateY(-5px); +} + +.resource-box h3 { + color: #2c3e50; + font-weight: 600; +} + +.resource-box .text-primary { + color: #3c7fb4 !important; +} + +.resource-box .text-success { + color: #28a745 !important; +} + +.resource-box .text-warning { + color: #ffc107 !important; +} + +.resource-box .text-info { + color: #17a2b8 !important; +} + +/* Card Header Enhancement */ +.card-header.bg-primary { + background: linear-gradient(135deg, #3c7fb4 0%, #2d5a87 100%) !important; +} + +.card-header h5 { + margin: 0; + font-weight: 600; +} + +/* Table Enhancements */ +.table-borderless td { + padding: 8px 12px; + vertical-align: middle; +} + +.table-borderless code { + background-color: #f8f9fa; + padding: 4px 8px; + border-radius: 4px; + font-size: 12px; + color: #e83e8c; +} + +/* Usage Details Box Enhancement */ +.usage-details { + border-radius: 12px !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); + transition: all 0.3s ease; +} + +.usage-details:hover { + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.12); + transform: translateY(-2px); +} + +/* VPS Control Button Styles - Hetzner Style */ +.vps-control-btn { + display: inline-flex !important; + align-items: center !important; + justify-content: center !important; + padding: 12px 24px !important; + border-radius: 25px !important; + margin: 8px 4px !important; + transition: all 0.3s ease !important; + text-decoration: none !important; + color: white !important; + font-size: 0.95rem !important; + font-weight: 600 !important; + min-height: 48px !important; + box-shadow: 0 3px 8px rgba(0,0,0,0.15) !important; + border: none !important; + position: relative !important; + overflow: hidden !important; +} + +.vps-control-btn:hover { + transform: translateY(-3px) !important; + box-shadow: 0 6px 16px rgba(0,0,0,0.2) !important; + text-decoration: none !important; + color: white !important; +} + +.vps-control-btn:active { + transform: translateY(-1px) !important; + box-shadow: 0 3px 8px rgba(0,0,0,0.15) !important; +} + +.vps-control-btn.start-btn { + background: linear-gradient(45deg, #28a745, #34ce57) !important; + color: white !important; +} + +.vps-control-btn.start-btn:hover { + background: linear-gradient(45deg, #218838, #28a745) !important; + color: white !important; +} + +.vps-control-btn.stop-btn { + background: linear-gradient(45deg, #dc3545, #ff4757) !important; + color: white !important; +} + +.vps-control-btn.stop-btn:hover { + background: linear-gradient(45deg, #c82333, #dc3545) !important; + color: white !important; +} + +.vps-control-btn.restart-btn { + background: linear-gradient(45deg, #fd7e14, #ff9f43) !important; + color: white !important; +} + +.vps-control-btn.restart-btn:hover { + background: linear-gradient(45deg, #e65100, #fd7e14) !important; + color: white !important; +} + +.vps-control-btn.vnc-btn { + background: linear-gradient(45deg, #6f42c1, #8854d0) !important; + color: white !important; +} + +.vps-control-btn.vnc-btn:hover { + background: linear-gradient(45deg, #5a32a3, #6f42c1) !important; + color: white !important; +} + +.vps-control-btn.vnc-btn img { + width: 20px !important; + height: 20px !important; + margin-right: 8px !important; + filter: brightness(0) invert(1); +} + +.vps-control-btn i { + margin-right: 8px !important; + font-size: 1.1rem !important; +} + +/* Mobile Responsive - Stack VPS Control Buttons Vertically */ +@media (max-width: 767px) { + .vps-control-btn { + display: block !important; + width: 100% !important; + margin: 8px 0 !important; + text-align: center !important; + } +} + +/* Responsive padding */ +@media (max-width: 768px) { + .card-body { + padding: 15px !important; + } + + .btn-lg { + padding: 10px 24px !important; + font-size: 14px !important; + } + + .resource-box { + padding: 15px 5px; + } +} \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/template/error.tpl b/modules/servers/ArkhostVPSAG/template/error.tpl new file mode 100644 index 0000000..3c3b2c1 --- /dev/null +++ b/modules/servers/ArkhostVPSAG/template/error.tpl @@ -0,0 +1,30 @@ +{** + * VPSAG WHMCS Server Provisioning version 1.4 + * + * @package WHMCS + * @copyright ArkHost + * @link https://arkhost.com + * @author ArkHost + *} + + + + + + + + + + + ArkHost - VPS Panel + + + + + + + \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/template/img/cloud.png b/modules/servers/ArkhostVPSAG/template/img/cloud.png new file mode 100644 index 0000000..fd805bb Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/cloud.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/edit.png b/modules/servers/ArkhostVPSAG/template/img/edit.png new file mode 100644 index 0000000..5a07524 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/edit.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/eye.png b/modules/servers/ArkhostVPSAG/template/img/eye.png new file mode 100644 index 0000000..87409f3 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/eye.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/installing.png b/modules/servers/ArkhostVPSAG/template/img/installing.png new file mode 100644 index 0000000..14adb20 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/installing.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/loading.png b/modules/servers/ArkhostVPSAG/template/img/loading.png new file mode 100644 index 0000000..b370a71 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/loading.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/lock.png b/modules/servers/ArkhostVPSAG/template/img/lock.png new file mode 100644 index 0000000..06025ed Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/lock.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/notice.png b/modules/servers/ArkhostVPSAG/template/img/notice.png new file mode 100644 index 0000000..4925a7b Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/notice.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/almalinux.png b/modules/servers/ArkhostVPSAG/template/img/os/almalinux.png new file mode 100644 index 0000000..34891bc Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/almalinux.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/centos.png b/modules/servers/ArkhostVPSAG/template/img/os/centos.png new file mode 100644 index 0000000..8cd1fa9 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/centos.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/debian.png b/modules/servers/ArkhostVPSAG/template/img/os/debian.png new file mode 100644 index 0000000..f52dcdb Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/debian.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/fedora.png b/modules/servers/ArkhostVPSAG/template/img/os/fedora.png new file mode 100644 index 0000000..6966c9c Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/fedora.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/iso.png b/modules/servers/ArkhostVPSAG/template/img/os/iso.png new file mode 100644 index 0000000..96a93e7 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/iso.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/lubuntu.png b/modules/servers/ArkhostVPSAG/template/img/os/lubuntu.png new file mode 100644 index 0000000..afdfd9f Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/lubuntu.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/mikrotik.png b/modules/servers/ArkhostVPSAG/template/img/os/mikrotik.png new file mode 100644 index 0000000..dfc5e7b Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/mikrotik.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/opensuse.png b/modules/servers/ArkhostVPSAG/template/img/os/opensuse.png new file mode 100644 index 0000000..077f59c Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/opensuse.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/others.png b/modules/servers/ArkhostVPSAG/template/img/os/others.png new file mode 100644 index 0000000..34fe6e4 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/others.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/rockylinux.png b/modules/servers/ArkhostVPSAG/template/img/os/rockylinux.png new file mode 100644 index 0000000..99363ca Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/rockylinux.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/ubuntu.png b/modules/servers/ArkhostVPSAG/template/img/os/ubuntu.png new file mode 100644 index 0000000..087c1e8 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/ubuntu.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/os/windows.png b/modules/servers/ArkhostVPSAG/template/img/os/windows.png new file mode 100644 index 0000000..43b2283 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/os/windows.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/running.png b/modules/servers/ArkhostVPSAG/template/img/running.png new file mode 100644 index 0000000..2429bcc Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/running.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/search.png b/modules/servers/ArkhostVPSAG/template/img/search.png new file mode 100644 index 0000000..b7af958 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/search.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/settings.png b/modules/servers/ArkhostVPSAG/template/img/settings.png new file mode 100644 index 0000000..bcf6362 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/settings.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/stopped.png b/modules/servers/ArkhostVPSAG/template/img/stopped.png new file mode 100644 index 0000000..c2ed128 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/stopped.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/suspended.png b/modules/servers/ArkhostVPSAG/template/img/suspended.png new file mode 100644 index 0000000..8a1de3c Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/suspended.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/under-cancellation.png b/modules/servers/ArkhostVPSAG/template/img/under-cancellation.png new file mode 100644 index 0000000..366b8dd Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/under-cancellation.png differ diff --git a/modules/servers/ArkhostVPSAG/template/img/vnc.png b/modules/servers/ArkhostVPSAG/template/img/vnc.png new file mode 100644 index 0000000..8793f95 Binary files /dev/null and b/modules/servers/ArkhostVPSAG/template/img/vnc.png differ diff --git a/modules/servers/ArkhostVPSAG/template/js/app.js b/modules/servers/ArkhostVPSAG/template/js/app.js new file mode 100644 index 0000000..d93418d --- /dev/null +++ b/modules/servers/ArkhostVPSAG/template/js/app.js @@ -0,0 +1,295 @@ + +function $_(id) { + return document.getElementById(id); +} + +function ArkHostVPS_API(action, alert = true, json = {}) { + ArkHostVPS_Loading(true); + + $.post(productURL + '&modop=custom&a=ClientAreaAPI&api=' + action, json, + function(data) { + if (data.result === 'success') { + switch (action) { + case 'IPv6': + $_('ipv6').parentElement.innerHTML = data.data; + data.data = 'IPv6 created: ' + data.data; + + break; + + case 'Graphs': + // Hide loading indicator (if it exists) + if ($_('graphs-loading')) $_('graphs-loading').style.display = 'none'; + if ($_('graphs-container')) $_('graphs-container').style.opacity = '1'; + + // Display graphs (they should be base64 images or img tags) + if ($_('cpu-graph')) $_('cpu-graph').innerHTML = data.cpu_img ? data.cpu_img : '

No CPU graph available

'; + if ($_('ram-graph')) $_('ram-graph').innerHTML = data.mem_img ? data.mem_img : '

No RAM graph available

'; + if ($_('disk-graph')) $_('disk-graph').innerHTML = data.disk_img ? data.disk_img : '

No Disk graph available

'; + if ($_('network-graph')) $_('network-graph').innerHTML = data.net_img ? data.net_img : '

No Network graph available

'; + + // Add graphs class for styling + if ($_('cpu-graph')) $_('cpu-graph').classList.add('graphs'); + if ($_('ram-graph')) $_('ram-graph').classList.add('graphs'); + if ($_('disk-graph')) $_('disk-graph').classList.add('graphs'); + if ($_('network-graph')) $_('network-graph').classList.add('graphs'); + + break; + + case 'Reinstall': + window.location.reload(); + break; + + case 'List backups': + const backupTable = $_('backupTable').getElementsByTagName('tbody')[0]; + + delete data.result; + $('#backupTable tbody').find('tr').remove(); + + for (let i = 0; i < Object.keys(data).length; i++) { + const backup = data[Object.keys(data)[i]]; + + const row = backupTable.insertRow(); + const date = row.insertCell(0); + const size = row.insertCell(1); + const type = row.insertCell(2); + const status = row.insertCell(3); + const actions = row.insertCell(4); + + date.innerHTML = new Date(backup.date).toLocaleString(); + size.innerHTML = (backup.size !== '' ? backup.size : '0.00GB'); + type.innerHTML = backup.type; + + if (backup.status === 'ok') { + status.innerHTML = '
Completed
'; + actions.innerHTML = ' '; + } else if (backup.status === 'preparing') { + status.innerHTML = '
Preparing
'; + } else if (backup.status === 'creating') { + status.innerHTML = '
Creating ' + backup.percentage + '%
'; + } else { + status.innerHTML = '
' + backup.status + '
'; + } + } + + break; + + case 'Create backup': + ArkHostVPS_API('List backups', false); + break; + + case 'Delete backup': + ArkHostVPS_API('List backups', false); + break; + + case 'Get Firewall rules': + const firewallTable = $_('firewallTable').getElementsByTagName('tbody')[0]; + + delete data.result; + $('#firewallTable tbody').find('tr:not(:last)').remove(); + + for (let i = 0; i < Object.keys(data).length; i++) { + const rule = data[Object.keys(data)[i]]; + + const row = firewallTable.insertRow(1); + const action = row.insertCell(0); + const port = row.insertCell(1); + const protocol = row.insertCell(2); + const source = row.insertCell(3); + const note = row.insertCell(4); + const actions = row.insertCell(5); + + action.innerHTML = rule.action; + port.innerHTML = rule.port; + protocol.innerHTML = rule.protocol; + source.innerHTML = rule.source; + note.innerHTML = rule.note; + actions.innerHTML = ''; + } + + $('#firewallTable tbody').append($('#firewallTable tbody tr:first')); + + break; + + case 'Add Firewall rules': + ArkHostVPS_API('Get Firewall rules', false); + break; + + case 'Delete Firewall rule': + ArkHostVPS_API('Get Firewall rules', false); + break; + + case 'Commit Firewall rules': + ArkHostVPS_API('Get Firewall rules', false); + break; + + case 'ISO Images': + const isoSelect = $_('isoID'); + + $('#isoID').empty(); + + for (let i = 0; i < data.iso.length; i++) { + const iso = data.iso[i]; + const option = document.createElement('option'); + + option.value = iso.id; + option.innerHTML = iso.iso_image; + option.selected = (data.current_iso !== 0 && data.current_iso == iso.id); + + isoSelect.appendChild(option); + } + } + + ArkHostVPS_Loading(false); + + if (alert) { + ArkHostVPS_Alert('success', (typeof data.data === 'string' ? data.data : lang.moduleactionsuccess)); + } + } else { + ArkHostVPS_Loading(false); + ArkHostVPS_Alert('error', (typeof data.message === 'string' ? data.message : lang.moduleactionfailed)); + } + } + ); +} + +function ArkHostVPS_VNC() { + window.open(productURL + '&modop=custom&a=VNC', '_blank', 'toolbar=0,location=0,menubar=0'); +} + + + + + +function ArkHostVPS_Loading(status) { + $_('loading').style.left = ((document.body.clientWidth - $('#loading').width()) / 2).toString() + 'px'; + + if (status) { + $('#loading').show(); + } else { + $('#loading').hide(); + } +} + + + +function ArkHostVPS_ChooseOS(button) { + var newOS = $_('newOS').value; + + if (newOS !== '0') { + newOS = $('[data-os="' + newOS + '"]')[0]; + newOS.classList.remove('SelectedOS'); + $_(newOS.dataset.group + '-os').classList.remove('selected'); + $_(newOS.dataset.group + '-version').innerText = 'CHOOSE VERSION'; + } + + $_('newOS').value = button.dataset.os; + button.classList.add('SelectedOS'); + $_(button.dataset.group + '-os').classList.add('selected'); + $_(button.dataset.group + '-version').innerText = button.innerText; +} + +function ArkHostVPS_ShowPassword() { + let passwordField = $_('vpsPassword'); + let showPasswordIcon = $_('showPasswordIcon'); + + if (passwordField.type === 'password') { + passwordField.type = 'text'; + showPasswordIcon.classList = 'fa-solid fa-eye-slash'; + } else { + passwordField.type = 'password'; + showPasswordIcon.classList = 'fa-solid fa-eye'; + } +} + +function ArkHostVPS_Alert(type, message) { + let Toast = Swal.mixin({ + toast: true, + position: 'top-end', + showConfirmButton: false, + timer: 3000 + }); + + Toast.fire({ + icon: type, + title: message + }); +} + +$(document).ready(function() { + $('#pills-tab').scrollingTabs({ + enableSwiping: true, + bootstrapVersion: 5, + cssClassLeftArrow: 'fa-solid fa-chevron-left', + cssClassRightArrow: 'fa-solid fa-chevron-right' + }); + + + + function ArkHostVPS_UpdateStatitics() { + if ($_('overview-tab').ariaSelected !== 'true') return timerServerLoads = setTimeout(ArkHostVPS_UpdateStatitics, 10000); + + clearTimeout(timerServerLoads); + + if (timerServerLoads) { + $.get(productURL + '&modop=custom&a=ClientAreaAPI&api=Server Info', + function(serverInfo) { + if (serverInfo.result === 'success') { + // Update CPU display: handle both decimal (0.0-1.0) and percentage (0-100) formats + var cpuDisplay; + if (serverInfo.cpu_usage <= 1) { + // Decimal format (0.0-1.0), convert to percentage + cpuDisplay = Math.round(serverInfo.cpu_usage * 100); + } else { + // Already percentage format (0-100) + cpuDisplay = Math.ceil(serverInfo.cpu_usage); + } + $('.used-cpu').html(cpuDisplay + '%'); + } else { + ArkHostVPS_Alert('error', (typeof serverInfo.message === 'string' ? serverInfo.message : lang.moduleactionfailed)); + } + } + ); + } else { + let serverInfo = serverInfoInitial; + serverInfo.ram_usage = serverInfo.ram_usage / 1000000000; + serverInfo.ram_usage_view = serverInfo.ram_usage.toFixed(2); + serverInfo.ram_percent = (serverInfo.ram_usage / serverInfo.ram) * 100; + serverInfo.ram_percent_view = serverInfo.ram_percent.toFixed(0); + + serverInfo.bandwidth_used_view = (serverInfo.bandwidth_used / 1024).toFixed(2); + serverInfo.bandwidth_percent = ((serverInfo.bandwidth_used / 1024) / serverInfo.bandwidth) * 100; + serverInfo.bandwidth_percent_view = serverInfo.bandwidth_percent.toFixed(0); + + // Disk usage not available from API, show total disk size instead + serverInfo.disk_used_view = serverInfo.disk; + serverInfo.disk_percent = 100; + serverInfo.disk_percent_view = '100'; + + $_('ramPercentBar').style.width = serverInfo.ram_percent_view + '%'; + $_('ramPercentBar').innerHTML = serverInfo.ram_percent_view + '%'; + $_('ramPercentVal').innerHTML = serverInfo.ram_usage_view + ' / ' + serverInfo.ram + ' GB'; + + $_('bandwidthPercentBar').style.width = serverInfo.bandwidth_percent_view + '%'; + $_('bandwidthPercentBar').innerHTML = serverInfo.bandwidth_percent_view + '%'; + $_('bandwidthPercentVal').innerHTML = serverInfo.bandwidth_used_view + ' / ' + serverInfo.bandwidth + ' TB'; + + $_('diskPercentVal').innerHTML = serverInfo.disk + ' GB'; + + // Update CPU display: handle both decimal (0.0-1.0) and percentage (0-100) formats + var cpuDisplay; + if (serverInfo.cpu_usage <= 1) { + // Decimal format (0.0-1.0), convert to percentage + cpuDisplay = Math.round(serverInfo.cpu_usage * 100); + } else { + // Already percentage format (0-100) + cpuDisplay = Math.ceil(serverInfo.cpu_usage); + } + $('.used-cpu').html(cpuDisplay + '%'); + } + + timerServerLoads = setTimeout(ArkHostVPS_UpdateStatitics, 10000); + } + + $_('ArkHostVPS').style.display = 'block'; + ArkHostVPS_UpdateStatitics(); +}); \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/template/js/app.min.js b/modules/servers/ArkhostVPSAG/template/js/app.min.js new file mode 100644 index 0000000..d93418d --- /dev/null +++ b/modules/servers/ArkhostVPSAG/template/js/app.min.js @@ -0,0 +1,295 @@ + +function $_(id) { + return document.getElementById(id); +} + +function ArkHostVPS_API(action, alert = true, json = {}) { + ArkHostVPS_Loading(true); + + $.post(productURL + '&modop=custom&a=ClientAreaAPI&api=' + action, json, + function(data) { + if (data.result === 'success') { + switch (action) { + case 'IPv6': + $_('ipv6').parentElement.innerHTML = data.data; + data.data = 'IPv6 created: ' + data.data; + + break; + + case 'Graphs': + // Hide loading indicator (if it exists) + if ($_('graphs-loading')) $_('graphs-loading').style.display = 'none'; + if ($_('graphs-container')) $_('graphs-container').style.opacity = '1'; + + // Display graphs (they should be base64 images or img tags) + if ($_('cpu-graph')) $_('cpu-graph').innerHTML = data.cpu_img ? data.cpu_img : '

No CPU graph available

'; + if ($_('ram-graph')) $_('ram-graph').innerHTML = data.mem_img ? data.mem_img : '

No RAM graph available

'; + if ($_('disk-graph')) $_('disk-graph').innerHTML = data.disk_img ? data.disk_img : '

No Disk graph available

'; + if ($_('network-graph')) $_('network-graph').innerHTML = data.net_img ? data.net_img : '

No Network graph available

'; + + // Add graphs class for styling + if ($_('cpu-graph')) $_('cpu-graph').classList.add('graphs'); + if ($_('ram-graph')) $_('ram-graph').classList.add('graphs'); + if ($_('disk-graph')) $_('disk-graph').classList.add('graphs'); + if ($_('network-graph')) $_('network-graph').classList.add('graphs'); + + break; + + case 'Reinstall': + window.location.reload(); + break; + + case 'List backups': + const backupTable = $_('backupTable').getElementsByTagName('tbody')[0]; + + delete data.result; + $('#backupTable tbody').find('tr').remove(); + + for (let i = 0; i < Object.keys(data).length; i++) { + const backup = data[Object.keys(data)[i]]; + + const row = backupTable.insertRow(); + const date = row.insertCell(0); + const size = row.insertCell(1); + const type = row.insertCell(2); + const status = row.insertCell(3); + const actions = row.insertCell(4); + + date.innerHTML = new Date(backup.date).toLocaleString(); + size.innerHTML = (backup.size !== '' ? backup.size : '0.00GB'); + type.innerHTML = backup.type; + + if (backup.status === 'ok') { + status.innerHTML = '
Completed
'; + actions.innerHTML = ' '; + } else if (backup.status === 'preparing') { + status.innerHTML = '
Preparing
'; + } else if (backup.status === 'creating') { + status.innerHTML = '
Creating ' + backup.percentage + '%
'; + } else { + status.innerHTML = '
' + backup.status + '
'; + } + } + + break; + + case 'Create backup': + ArkHostVPS_API('List backups', false); + break; + + case 'Delete backup': + ArkHostVPS_API('List backups', false); + break; + + case 'Get Firewall rules': + const firewallTable = $_('firewallTable').getElementsByTagName('tbody')[0]; + + delete data.result; + $('#firewallTable tbody').find('tr:not(:last)').remove(); + + for (let i = 0; i < Object.keys(data).length; i++) { + const rule = data[Object.keys(data)[i]]; + + const row = firewallTable.insertRow(1); + const action = row.insertCell(0); + const port = row.insertCell(1); + const protocol = row.insertCell(2); + const source = row.insertCell(3); + const note = row.insertCell(4); + const actions = row.insertCell(5); + + action.innerHTML = rule.action; + port.innerHTML = rule.port; + protocol.innerHTML = rule.protocol; + source.innerHTML = rule.source; + note.innerHTML = rule.note; + actions.innerHTML = ''; + } + + $('#firewallTable tbody').append($('#firewallTable tbody tr:first')); + + break; + + case 'Add Firewall rules': + ArkHostVPS_API('Get Firewall rules', false); + break; + + case 'Delete Firewall rule': + ArkHostVPS_API('Get Firewall rules', false); + break; + + case 'Commit Firewall rules': + ArkHostVPS_API('Get Firewall rules', false); + break; + + case 'ISO Images': + const isoSelect = $_('isoID'); + + $('#isoID').empty(); + + for (let i = 0; i < data.iso.length; i++) { + const iso = data.iso[i]; + const option = document.createElement('option'); + + option.value = iso.id; + option.innerHTML = iso.iso_image; + option.selected = (data.current_iso !== 0 && data.current_iso == iso.id); + + isoSelect.appendChild(option); + } + } + + ArkHostVPS_Loading(false); + + if (alert) { + ArkHostVPS_Alert('success', (typeof data.data === 'string' ? data.data : lang.moduleactionsuccess)); + } + } else { + ArkHostVPS_Loading(false); + ArkHostVPS_Alert('error', (typeof data.message === 'string' ? data.message : lang.moduleactionfailed)); + } + } + ); +} + +function ArkHostVPS_VNC() { + window.open(productURL + '&modop=custom&a=VNC', '_blank', 'toolbar=0,location=0,menubar=0'); +} + + + + + +function ArkHostVPS_Loading(status) { + $_('loading').style.left = ((document.body.clientWidth - $('#loading').width()) / 2).toString() + 'px'; + + if (status) { + $('#loading').show(); + } else { + $('#loading').hide(); + } +} + + + +function ArkHostVPS_ChooseOS(button) { + var newOS = $_('newOS').value; + + if (newOS !== '0') { + newOS = $('[data-os="' + newOS + '"]')[0]; + newOS.classList.remove('SelectedOS'); + $_(newOS.dataset.group + '-os').classList.remove('selected'); + $_(newOS.dataset.group + '-version').innerText = 'CHOOSE VERSION'; + } + + $_('newOS').value = button.dataset.os; + button.classList.add('SelectedOS'); + $_(button.dataset.group + '-os').classList.add('selected'); + $_(button.dataset.group + '-version').innerText = button.innerText; +} + +function ArkHostVPS_ShowPassword() { + let passwordField = $_('vpsPassword'); + let showPasswordIcon = $_('showPasswordIcon'); + + if (passwordField.type === 'password') { + passwordField.type = 'text'; + showPasswordIcon.classList = 'fa-solid fa-eye-slash'; + } else { + passwordField.type = 'password'; + showPasswordIcon.classList = 'fa-solid fa-eye'; + } +} + +function ArkHostVPS_Alert(type, message) { + let Toast = Swal.mixin({ + toast: true, + position: 'top-end', + showConfirmButton: false, + timer: 3000 + }); + + Toast.fire({ + icon: type, + title: message + }); +} + +$(document).ready(function() { + $('#pills-tab').scrollingTabs({ + enableSwiping: true, + bootstrapVersion: 5, + cssClassLeftArrow: 'fa-solid fa-chevron-left', + cssClassRightArrow: 'fa-solid fa-chevron-right' + }); + + + + function ArkHostVPS_UpdateStatitics() { + if ($_('overview-tab').ariaSelected !== 'true') return timerServerLoads = setTimeout(ArkHostVPS_UpdateStatitics, 10000); + + clearTimeout(timerServerLoads); + + if (timerServerLoads) { + $.get(productURL + '&modop=custom&a=ClientAreaAPI&api=Server Info', + function(serverInfo) { + if (serverInfo.result === 'success') { + // Update CPU display: handle both decimal (0.0-1.0) and percentage (0-100) formats + var cpuDisplay; + if (serverInfo.cpu_usage <= 1) { + // Decimal format (0.0-1.0), convert to percentage + cpuDisplay = Math.round(serverInfo.cpu_usage * 100); + } else { + // Already percentage format (0-100) + cpuDisplay = Math.ceil(serverInfo.cpu_usage); + } + $('.used-cpu').html(cpuDisplay + '%'); + } else { + ArkHostVPS_Alert('error', (typeof serverInfo.message === 'string' ? serverInfo.message : lang.moduleactionfailed)); + } + } + ); + } else { + let serverInfo = serverInfoInitial; + serverInfo.ram_usage = serverInfo.ram_usage / 1000000000; + serverInfo.ram_usage_view = serverInfo.ram_usage.toFixed(2); + serverInfo.ram_percent = (serverInfo.ram_usage / serverInfo.ram) * 100; + serverInfo.ram_percent_view = serverInfo.ram_percent.toFixed(0); + + serverInfo.bandwidth_used_view = (serverInfo.bandwidth_used / 1024).toFixed(2); + serverInfo.bandwidth_percent = ((serverInfo.bandwidth_used / 1024) / serverInfo.bandwidth) * 100; + serverInfo.bandwidth_percent_view = serverInfo.bandwidth_percent.toFixed(0); + + // Disk usage not available from API, show total disk size instead + serverInfo.disk_used_view = serverInfo.disk; + serverInfo.disk_percent = 100; + serverInfo.disk_percent_view = '100'; + + $_('ramPercentBar').style.width = serverInfo.ram_percent_view + '%'; + $_('ramPercentBar').innerHTML = serverInfo.ram_percent_view + '%'; + $_('ramPercentVal').innerHTML = serverInfo.ram_usage_view + ' / ' + serverInfo.ram + ' GB'; + + $_('bandwidthPercentBar').style.width = serverInfo.bandwidth_percent_view + '%'; + $_('bandwidthPercentBar').innerHTML = serverInfo.bandwidth_percent_view + '%'; + $_('bandwidthPercentVal').innerHTML = serverInfo.bandwidth_used_view + ' / ' + serverInfo.bandwidth + ' TB'; + + $_('diskPercentVal').innerHTML = serverInfo.disk + ' GB'; + + // Update CPU display: handle both decimal (0.0-1.0) and percentage (0-100) formats + var cpuDisplay; + if (serverInfo.cpu_usage <= 1) { + // Decimal format (0.0-1.0), convert to percentage + cpuDisplay = Math.round(serverInfo.cpu_usage * 100); + } else { + // Already percentage format (0-100) + cpuDisplay = Math.ceil(serverInfo.cpu_usage); + } + $('.used-cpu').html(cpuDisplay + '%'); + } + + timerServerLoads = setTimeout(ArkHostVPS_UpdateStatitics, 10000); + } + + $_('ArkHostVPS').style.display = 'block'; + ArkHostVPS_UpdateStatitics(); +}); \ No newline at end of file diff --git a/modules/servers/ArkhostVPSAG/template/js/bundle.min.js b/modules/servers/ArkhostVPSAG/template/js/bundle.min.js new file mode 100644 index 0000000..fa77901 --- /dev/null +++ b/modules/servers/ArkhostVPSAG/template/js/bundle.min.js @@ -0,0 +1,174 @@ +/*! + * Bootstrap v5.2.0 (https://getbootstrap.com/) + * Copyright 2011-2022 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=t=>{if(!o(t)||0===t.getClientRects().length)return!1;const e="visible"===getComputedStyle(t).getPropertyValue("visibility"),i=t.closest("details:not([open])");if(!i)return e;if(i!==t){const e=t.closest("summary");if(e&&e.parentNode!==i)return!1;if(null===e)return!1}return e},l=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),c=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?c(t.parentNode):null},h=()=>{},d=t=>{t.offsetHeight},u=()=>window.jQuery&&!document.body.hasAttribute("data-bs-no-jquery")?window.jQuery:null,f=[],p=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=u();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(f.length||document.addEventListener("DOMContentLoaded",(()=>{for(const t of f)t()})),f.push(e)):e()},m=t=>{"function"==typeof t&&t()},_=(e,i,n=!0)=>{if(!n)return void m(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),m(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},b=(t,e,i,n)=>{const s=t.length;let o=t.indexOf(e);return-1===o?!i&&n?t[s-1]:t[0]:(o+=i?1:-1,n&&(o=(o+s)%s),t[Math.max(0,Math.min(o,s-1))])},v=/[^.]*(?=\..*)\.|.*/,y=/\..*/,w=/::\d+$/,A={};let E=1;const T={mouseenter:"mouseover",mouseleave:"mouseout"},C=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function O(t,e){return e&&`${e}::${E++}`||t.uidEvent||E++}function x(t){const e=O(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function k(t,e,i=null){return Object.values(t).find((t=>t.callable===e&&t.delegationSelector===i))}function L(t,e,i){const n="string"==typeof e,s=n?i:e||i;let o=N(t);return C.has(o)||(o=t),[n,s,o]}function D(t,e,i,n,s){if("string"!=typeof e||!t)return;let[o,r,a]=L(e,i,n);if(e in T){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};r=t(r)}const l=x(t),c=l[a]||(l[a]={}),h=k(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=O(r,e.replace(v,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(const a of o)if(a===r)return j(s,{delegateTarget:r}),n.oneOff&&P.off(t,s.type,e,i),i.apply(r,[s])}}(t,i,r):function(t,e){return function i(n){return j(n,{delegateTarget:t}),i.oneOff&&P.off(t,n.type,e),e.apply(t,[n])}}(t,r);u.delegationSelector=o?i:null,u.callable=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function S(t,e,i,n,s){const o=k(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function I(t,e,i,n){const s=e[i]||{};for(const o of Object.keys(s))if(o.includes(n)){const n=s[o];S(t,e,i,n.callable,n.delegationSelector)}}function N(t){return t=t.replace(y,""),T[t]||t}const P={on(t,e,i,n){D(t,e,i,n,!1)},one(t,e,i,n){D(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=L(e,i,n),a=r!==e,l=x(t),c=l[r]||{},h=e.startsWith(".");if(void 0===o){if(h)for(const i of Object.keys(l))I(t,l,i,e.slice(1));for(const i of Object.keys(c)){const n=i.replace(w,"");if(!a||e.includes(n)){const e=c[i];S(t,l,r,e.callable,e.delegationSelector)}}}else{if(!Object.keys(c).length)return;S(t,l,r,o,s?i:null)}},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=u();let s=null,o=!0,r=!0,a=!1;e!==N(e)&&n&&(s=n.Event(e,i),n(t).trigger(s),o=!s.isPropagationStopped(),r=!s.isImmediatePropagationStopped(),a=s.isDefaultPrevented());let l=new Event(e,{bubbles:o,cancelable:!0});return l=j(l,i),a&&l.preventDefault(),r&&t.dispatchEvent(l),l.defaultPrevented&&s&&s.preventDefault(),l}};function j(t,e){for(const[i,n]of Object.entries(e||{}))try{t[i]=n}catch(e){Object.defineProperty(t,i,{configurable:!0,get:()=>n})}return t}const M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};function $(t){if("true"===t)return!0;if("false"===t)return!1;if(t===Number(t).toString())return Number(t);if(""===t||"null"===t)return null;if("string"!=typeof t)return t;try{return JSON.parse(decodeURIComponent(t))}catch(e){return t}}function W(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}const B={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${W(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${W(e)}`)},getDataAttributes(t){if(!t)return{};const e={},i=Object.keys(t.dataset).filter((t=>t.startsWith("bs")&&!t.startsWith("bsConfig")));for(const n of i){let i=n.replace(/^bs/,"");i=i.charAt(0).toLowerCase()+i.slice(1,i.length),e[i]=$(t.dataset[n])}return e},getDataAttribute:(t,e)=>$(t.getAttribute(`data-bs-${W(e)}`))};class F{static get Default(){return{}}static get DefaultType(){return{}}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}_getConfig(t){return t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t}_mergeConfigObj(t,e){const i=o(e)?B.getDataAttribute(e,"config"):{};return{...this.constructor.Default,..."object"==typeof i?i:{},...o(e)?B.getDataAttributes(e):{},..."object"==typeof t?t:{}}}_typeCheckConfig(t,e=this.constructor.DefaultType){for(const n of Object.keys(e)){const s=e[n],r=t[n],a=o(r)?"element":null==(i=r)?`${i}`:Object.prototype.toString.call(i).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(s).test(a))throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}var i}}class z extends F{constructor(t,e){super(),(t=r(t))&&(this._element=t,this._config=this._getConfig(e),H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),P.off(this._element,this.constructor.EVENT_KEY);for(const t of Object.getOwnPropertyNames(this))this[t]=null}_queueCallback(t,e,i=!0){_(t,e,i)}_getConfig(t){return t=this._mergeConfigObj(t,this._element),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.2.0"}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}static eventName(t){return`${t}${this.EVENT_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;P.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),l(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class q extends z{static get NAME(){return"alert"}close(){if(P.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),P.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=q.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(q,"close"),g(q);const V='[data-bs-toggle="button"]';class K extends z{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=K.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}P.on(document,"click.bs.button.data-api",V,(t=>{t.preventDefault();const e=t.target.closest(V);K.getOrCreateInstance(e).toggle()})),g(K);const Q={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode.closest(e);for(;n;)i.push(n),n=n.parentNode.closest(e);return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(",");return this.find(e,t).filter((t=>!l(t)&&a(t)))}},X={endCallback:null,leftCallback:null,rightCallback:null},Y={endCallback:"(function|null)",leftCallback:"(function|null)",rightCallback:"(function|null)"};class U extends F{constructor(t,e){super(),this._element=t,t&&U.isSupported()&&(this._config=this._getConfig(e),this._deltaX=0,this._supportPointerEvents=Boolean(window.PointerEvent),this._initEvents())}static get Default(){return X}static get DefaultType(){return Y}static get NAME(){return"swipe"}dispose(){P.off(this._element,".bs.swipe")}_start(t){this._supportPointerEvents?this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX):this._deltaX=t.touches[0].clientX}_end(t){this._eventIsPointerPenTouch(t)&&(this._deltaX=t.clientX-this._deltaX),this._handleSwipe(),m(this._config.endCallback)}_move(t){this._deltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this._deltaX}_handleSwipe(){const t=Math.abs(this._deltaX);if(t<=40)return;const e=t/this._deltaX;this._deltaX=0,e&&m(e>0?this._config.rightCallback:this._config.leftCallback)}_initEvents(){this._supportPointerEvents?(P.on(this._element,"pointerdown.bs.swipe",(t=>this._start(t))),P.on(this._element,"pointerup.bs.swipe",(t=>this._end(t))),this._element.classList.add("pointer-event")):(P.on(this._element,"touchstart.bs.swipe",(t=>this._start(t))),P.on(this._element,"touchmove.bs.swipe",(t=>this._move(t))),P.on(this._element,"touchend.bs.swipe",(t=>this._end(t))))}_eventIsPointerPenTouch(t){return this._supportPointerEvents&&("pen"===t.pointerType||"touch"===t.pointerType)}static isSupported(){return"ontouchstart"in document.documentElement||navigator.maxTouchPoints>0}}const G="next",J="prev",Z="left",tt="right",et="slid.bs.carousel",it="carousel",nt="active",st={ArrowLeft:tt,ArrowRight:Z},ot={interval:5e3,keyboard:!0,pause:"hover",ride:!1,touch:!0,wrap:!0},rt={interval:"(number|boolean)",keyboard:"boolean",pause:"(string|boolean)",ride:"(boolean|string)",touch:"boolean",wrap:"boolean"};class at extends z{constructor(t,e){super(t,e),this._interval=null,this._activeElement=null,this._isSliding=!1,this.touchTimeout=null,this._swipeHelper=null,this._indicatorsElement=Q.findOne(".carousel-indicators",this._element),this._addEventListeners(),this._config.ride===it&&this.cycle()}static get Default(){return ot}static get DefaultType(){return rt}static get NAME(){return"carousel"}next(){this._slide(G)}nextWhenVisible(){!document.hidden&&a(this._element)&&this.next()}prev(){this._slide(J)}pause(){this._isSliding&&s(this._element),this._clearInterval()}cycle(){this._clearInterval(),this._updateInterval(),this._interval=setInterval((()=>this.nextWhenVisible()),this._config.interval)}_maybeEnableCycle(){this._config.ride&&(this._isSliding?P.one(this._element,et,(()=>this.cycle())):this.cycle())}to(t){const e=this._getItems();if(t>e.length-1||t<0)return;if(this._isSliding)return void P.one(this._element,et,(()=>this.to(t)));const i=this._getItemIndex(this._getActive());if(i===t)return;const n=t>i?G:J;this._slide(n,e[t])}dispose(){this._swipeHelper&&this._swipeHelper.dispose(),super.dispose()}_configAfterMerge(t){return t.defaultInterval=t.interval,t}_addEventListeners(){this._config.keyboard&&P.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(P.on(this._element,"mouseenter.bs.carousel",(()=>this.pause())),P.on(this._element,"mouseleave.bs.carousel",(()=>this._maybeEnableCycle()))),this._config.touch&&U.isSupported()&&this._addTouchEventListeners()}_addTouchEventListeners(){for(const t of Q.find(".carousel-item img",this._element))P.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()));const t={leftCallback:()=>this._slide(this._directionToOrder(Z)),rightCallback:()=>this._slide(this._directionToOrder(tt)),endCallback:()=>{"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((()=>this._maybeEnableCycle()),500+this._config.interval))}};this._swipeHelper=new U(this._element,t)}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=st[t.key];e&&(t.preventDefault(),this._slide(this._directionToOrder(e)))}_getItemIndex(t){return this._getItems().indexOf(t)}_setActiveIndicatorElement(t){if(!this._indicatorsElement)return;const e=Q.findOne(".active",this._indicatorsElement);e.classList.remove(nt),e.removeAttribute("aria-current");const i=Q.findOne(`[data-bs-slide-to="${t}"]`,this._indicatorsElement);i&&(i.classList.add(nt),i.setAttribute("aria-current","true"))}_updateInterval(){const t=this._activeElement||this._getActive();if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);this._config.interval=e||this._config.defaultInterval}_slide(t,e=null){if(this._isSliding)return;const i=this._getActive(),n=t===G,s=e||b(this._getItems(),i,n,this._config.wrap);if(s===i)return;const o=this._getItemIndex(s),r=e=>P.trigger(this._element,e,{relatedTarget:s,direction:this._orderToDirection(t),from:this._getItemIndex(i),to:o});if(r("slide.bs.carousel").defaultPrevented)return;if(!i||!s)return;const a=Boolean(this._interval);this.pause(),this._isSliding=!0,this._setActiveIndicatorElement(o),this._activeElement=s;const l=n?"carousel-item-start":"carousel-item-end",c=n?"carousel-item-next":"carousel-item-prev";s.classList.add(c),d(s),i.classList.add(l),s.classList.add(l),this._queueCallback((()=>{s.classList.remove(l,c),s.classList.add(nt),i.classList.remove(nt,c,l),this._isSliding=!1,r(et)}),i,this._isAnimated()),a&&this.cycle()}_isAnimated(){return this._element.classList.contains("slide")}_getActive(){return Q.findOne(".active.carousel-item",this._element)}_getItems(){return Q.find(".carousel-item",this._element)}_clearInterval(){this._interval&&(clearInterval(this._interval),this._interval=null)}_directionToOrder(t){return p()?t===Z?J:G:t===Z?G:J}_orderToDirection(t){return p()?t===J?Z:tt:t===J?tt:Z}static jQueryInterface(t){return this.each((function(){const e=at.getOrCreateInstance(this,t);if("number"!=typeof t){if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}else e.to(t)}))}}P.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",(function(t){const e=n(this);if(!e||!e.classList.contains(it))return;t.preventDefault();const i=at.getOrCreateInstance(e),s=this.getAttribute("data-bs-slide-to");return s?(i.to(s),void i._maybeEnableCycle()):"next"===B.getDataAttribute(this,"slide")?(i.next(),void i._maybeEnableCycle()):(i.prev(),void i._maybeEnableCycle())})),P.on(window,"load.bs.carousel.data-api",(()=>{const t=Q.find('[data-bs-ride="carousel"]');for(const e of t)at.getOrCreateInstance(e)})),g(at);const lt="show",ct="collapse",ht="collapsing",dt='[data-bs-toggle="collapse"]',ut={parent:null,toggle:!0},ft={parent:"(null|element)",toggle:"boolean"};class pt extends z{constructor(t,e){super(t,e),this._isTransitioning=!1,this._triggerArray=[];const n=Q.find(dt);for(const t of n){const e=i(t),n=Q.find(e).filter((t=>t===this._element));null!==e&&n.length&&this._triggerArray.push(t)}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return ut}static get DefaultType(){return ft}static get NAME(){return"collapse"}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t=[];if(this._config.parent&&(t=this._getFirstLevelChildren(".collapse.show, .collapse.collapsing").filter((t=>t!==this._element)).map((t=>pt.getOrCreateInstance(t,{toggle:!1})))),t.length&&t[0]._isTransitioning)return;if(P.trigger(this._element,"show.bs.collapse").defaultPrevented)return;for(const e of t)e.hide();const e=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[e]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const i=`scroll${e[0].toUpperCase()+e.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[e]="",P.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[e]=`${this._element[i]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(P.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,d(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);for(const t of this._triggerArray){const e=n(t);e&&!this._isShown(e)&&this._addAriaAndCollapsedClass([t],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),P.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_configAfterMerge(t){return t.toggle=Boolean(t.toggle),t.parent=r(t.parent),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=this._getFirstLevelChildren(dt);for(const e of t){const t=n(e);t&&this._addAriaAndCollapsedClass([e],this._isShown(t))}}_getFirstLevelChildren(t){const e=Q.find(":scope .collapse .collapse",this._config.parent);return Q.find(t,this._config.parent).filter((t=>!e.includes(t)))}_addAriaAndCollapsedClass(t,e){if(t.length)for(const i of t)i.classList.toggle("collapsed",!e),i.setAttribute("aria-expanded",e)}static jQueryInterface(t){const e={};return"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1),this.each((function(){const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}P.on(document,"click.bs.collapse.data-api",dt,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this),n=Q.find(e);for(const t of n)pt.getOrCreateInstance(t,{toggle:!1}).toggle()})),g(pt);var gt="top",mt="bottom",_t="right",bt="left",vt="auto",yt=[gt,mt,_t,bt],wt="start",At="end",Et="clippingParents",Tt="viewport",Ct="popper",Ot="reference",xt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+At])}),[]),kt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+At])}),[]),Lt="beforeRead",Dt="read",St="afterRead",It="beforeMain",Nt="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",$t=[Lt,Dt,St,It,Nt,Pt,jt,Mt,Ht];function Wt(t){return t?(t.nodeName||"").toLowerCase():null}function Bt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function Ft(t){return t instanceof Bt(t).Element||t instanceof Element}function zt(t){return t instanceof Bt(t).HTMLElement||t instanceof HTMLElement}function Rt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Bt(t).ShadowRoot||t instanceof ShadowRoot)}const qt={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Wt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Wt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Vt(t){return t.split("-")[0]}var Kt=Math.max,Qt=Math.min,Xt=Math.round;function Yt(t,e){void 0===e&&(e=!1);var i=t.getBoundingClientRect(),n=1,s=1;if(zt(t)&&e){var o=t.offsetHeight,r=t.offsetWidth;r>0&&(n=Xt(i.width)/r||1),o>0&&(s=Xt(i.height)/o||1)}return{width:i.width/n,height:i.height/s,top:i.top/s,right:i.right/n,bottom:i.bottom/s,left:i.left/n,x:i.left/n,y:i.top/s}}function Ut(t){var e=Yt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Gt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&Rt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Jt(t){return Bt(t).getComputedStyle(t)}function Zt(t){return["table","td","th"].indexOf(Wt(t))>=0}function te(t){return((Ft(t)?t.ownerDocument:t.document)||window.document).documentElement}function ee(t){return"html"===Wt(t)?t:t.assignedSlot||t.parentNode||(Rt(t)?t.host:null)||te(t)}function ie(t){return zt(t)&&"fixed"!==Jt(t).position?t.offsetParent:null}function ne(t){for(var e=Bt(t),i=ie(t);i&&Zt(i)&&"static"===Jt(i).position;)i=ie(i);return i&&("html"===Wt(i)||"body"===Wt(i)&&"static"===Jt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Jt(t).position)return null;var i=ee(t);for(Rt(i)&&(i=i.host);zt(i)&&["html","body"].indexOf(Wt(i))<0;){var n=Jt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function se(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}function oe(t,e,i){return Kt(t,Qt(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Vt(i.placement),l=se(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Ut(o),u="y"===l?gt:bt,f="y"===l?mt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],g=r[l]-i.rects.reference[l],m=ne(o),_=m?"y"===l?m.clientHeight||0:m.clientWidth||0:0,b=p/2-g/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,A=oe(v,w,y),E=l;i.modifiersData[n]=((e={})[E]=A,e.centerOffset=A-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Gt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=t.isFixed,u=r.x,f=void 0===u?0:u,p=r.y,g=void 0===p?0:p,m="function"==typeof h?h({x:f,y:g}):{x:f,y:g};f=m.x,g=m.y;var _=r.hasOwnProperty("x"),b=r.hasOwnProperty("y"),v=bt,y=gt,w=window;if(c){var A=ne(i),E="clientHeight",T="clientWidth";A===Bt(i)&&"static"!==Jt(A=te(i)).position&&"absolute"===a&&(E="scrollHeight",T="scrollWidth"),(s===gt||(s===bt||s===_t)&&o===At)&&(y=mt,g-=(d&&A===w&&w.visualViewport?w.visualViewport.height:A[E])-n.height,g*=l?1:-1),s!==bt&&(s!==gt&&s!==mt||o!==At)||(v=_t,f-=(d&&A===w&&w.visualViewport?w.visualViewport.width:A[T])-n.width,f*=l?1:-1)}var C,O=Object.assign({position:a},c&&he),x=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:Xt(e*n)/n||0,y:Xt(i*n)/n||0}}({x:f,y:g}):{x:f,y:g};return f=x.x,g=x.y,l?Object.assign({},O,((C={})[y]=b?"0":"",C[v]=_?"0":"",C.transform=(w.devicePixelRatio||1)<=1?"translate("+f+"px, "+g+"px)":"translate3d("+f+"px, "+g+"px, 0)",C)):Object.assign({},O,((e={})[y]=b?g+"px":"",e[v]=_?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Vt(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s,isFixed:"fixed"===e.options.strategy};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Bt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var ge={left:"right",right:"left",bottom:"top",top:"bottom"};function me(t){return t.replace(/left|right|bottom|top/g,(function(t){return ge[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Bt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Yt(te(t)).left+ve(t).scrollLeft}function we(t){var e=Jt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ae(t){return["html","body","#document"].indexOf(Wt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ae(ee(t))}function Ee(t,e){var i;void 0===e&&(e=[]);var n=Ae(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Bt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ee(ee(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Ce(t,e){return e===Tt?Te(function(t){var e=Bt(t),i=te(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):Ft(e)?function(t){var e=Yt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=te(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=Kt(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=Kt(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Jt(s||i).direction&&(a+=Kt(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(te(t)))}function Oe(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Vt(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case gt:e={x:a,y:i.y-n.height};break;case mt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?se(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case At:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function xe(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?Et:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ct:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,g=re("number"!=typeof p?p:ae(p,yt)),m=h===Ct?Ot:Ct,_=t.rects.popper,b=t.elements[u?m:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ee(ee(t)),i=["absolute","fixed"].indexOf(Jt(t).position)>=0&&zt(t)?ne(t):t;return Ft(i)?e.filter((function(t){return Ft(t)&&Gt(t,i)&&"body"!==Wt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Ce(t,i);return e.top=Kt(n.top,e.top),e.right=Qt(n.right,e.right),e.bottom=Qt(n.bottom,e.bottom),e.left=Kt(n.left,e.left),e}),Ce(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}(Ft(b)?b:b.contextElement||te(t.elements.popper),r,l),y=Yt(t.elements.reference),w=Oe({reference:y,element:_,strategy:"absolute",placement:s}),A=Te(Object.assign({},_,w)),E=h===Ct?A:y,T={top:v.top-E.top+g.top,bottom:E.bottom-v.bottom+g.bottom,left:v.left-E.left+g.left,right:E.right-v.right+g.right},C=t.modifiersData.offset;if(h===Ct&&C){var O=C[s];Object.keys(T).forEach((function(t){var e=[_t,mt].indexOf(t)>=0?1:-1,i=[gt,mt].indexOf(t)>=0?"y":"x";T[t]+=O[i]*e}))}return T}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?kt:l,h=ce(n),d=h?a?xt:xt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=xe(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Vt(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const Le={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,g=i.allowedAutoPlacements,m=e.options.placement,_=Vt(m),b=l||(_!==m&&p?function(t){if(Vt(t)===vt)return[];var e=me(t);return[be(t),e,be(e)]}(m):[me(m)]),v=[m].concat(b).reduce((function(t,i){return t.concat(Vt(i)===vt?ke(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:g}):i)}),[]),y=e.rects.reference,w=e.rects.popper,A=new Map,E=!0,T=v[0],C=0;C=0,D=L?"width":"height",S=xe(e,{placement:O,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),I=L?k?_t:bt:k?mt:gt;y[D]>w[D]&&(I=me(I));var N=me(I),P=[];if(o&&P.push(S[x]<=0),a&&P.push(S[I]<=0,S[N]<=0),P.every((function(t){return t}))){T=O,E=!1;break}A.set(O,P)}if(E)for(var j=function(t){var e=v.find((function(e){var i=A.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[gt,_t,mt,bt].some((function(e){return t[e]>=0}))}const Ie={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=xe(e,{elementContext:"reference"}),a=xe(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ne={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=kt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Vt(t),s=[bt,gt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Oe({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,g=void 0===p?0:p,m=xe(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Vt(e.placement),b=ce(e.placement),v=!b,y=se(_),w="x"===y?"y":"x",A=e.modifiersData.popperOffsets,E=e.rects.reference,T=e.rects.popper,C="function"==typeof g?g(Object.assign({},e.rects,{placement:e.placement})):g,O="number"==typeof C?{mainAxis:C,altAxis:C}:Object.assign({mainAxis:0,altAxis:0},C),x=e.modifiersData.offset?e.modifiersData.offset[e.placement]:null,k={x:0,y:0};if(A){if(o){var L,D="y"===y?gt:bt,S="y"===y?mt:_t,I="y"===y?"height":"width",N=A[y],P=N+m[D],j=N-m[S],M=f?-T[I]/2:0,H=b===wt?E[I]:T[I],$=b===wt?-T[I]:-E[I],W=e.elements.arrow,B=f&&W?Ut(W):{width:0,height:0},F=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},z=F[D],R=F[S],q=oe(0,E[I],B[I]),V=v?E[I]/2-M-q-z-O.mainAxis:H-q-z-O.mainAxis,K=v?-E[I]/2+M+q+R+O.mainAxis:$+q+R+O.mainAxis,Q=e.elements.arrow&&ne(e.elements.arrow),X=Q?"y"===y?Q.clientTop||0:Q.clientLeft||0:0,Y=null!=(L=null==x?void 0:x[y])?L:0,U=N+K-Y,G=oe(f?Qt(P,N+V-Y-X):P,N,f?Kt(j,U):j);A[y]=G,k[y]=G-N}if(a){var J,Z="x"===y?gt:bt,tt="x"===y?mt:_t,et=A[w],it="y"===w?"height":"width",nt=et+m[Z],st=et-m[tt],ot=-1!==[gt,bt].indexOf(_),rt=null!=(J=null==x?void 0:x[w])?J:0,at=ot?nt:et-E[it]-T[it]-rt+O.altAxis,lt=ot?et+E[it]+T[it]-rt-O.altAxis:st,ct=f&&ot?function(t,e,i){var n=oe(t,e,i);return n>i?i:n}(at,et,lt):oe(f?at:nt,et,f?lt:st);A[w]=ct,k[w]=ct-et}e.modifiersData[n]=k}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n,s,o=zt(e),r=zt(e)&&function(t){var e=t.getBoundingClientRect(),i=Xt(e.width)/t.offsetWidth||1,n=Xt(e.height)/t.offsetHeight||1;return 1!==i||1!==n}(e),a=te(e),l=Yt(t,r),c={scrollLeft:0,scrollTop:0},h={x:0,y:0};return(o||!o&&!i)&&(("body"!==Wt(e)||we(a))&&(c=(n=e)!==Bt(n)&&zt(n)?{scrollLeft:(s=n).scrollLeft,scrollTop:s.scrollTop}:ve(n)),zt(e)?((h=Yt(e,!0)).x+=e.clientLeft,h.y+=e.clientTop):a&&(h.x=ye(a))),{x:l.left+c.scrollLeft-h.x,y:l.top+c.scrollTop-h.y,width:l.width,height:l.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var $e={placement:"bottom",modifiers:[],strategy:"absolute"};function We(){for(var t=arguments.length,e=new Array(t),i=0;iNumber.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return(this._inNavbar||"static"===this._config.display)&&(B.setDataAttribute(this._menu,"popper","static"),t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=Q.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter((t=>a(t)));i.length&&b(i,e,t===Qe,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=li.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(2===t.button||"keyup"===t.type&&"Tab"!==t.key)return;const e=Q.find(Je);for(const i of e){const e=li.getInstance(i);if(!e||!1===e._config.autoClose)continue;const n=t.composedPath(),s=n.includes(e._menu);if(n.includes(e._element)||"inside"===e._config.autoClose&&!s||"outside"===e._config.autoClose&&s)continue;if(e._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;const o={relatedTarget:e._element};"click"===t.type&&(o.clickEvent=t),e._completeHide(o)}}static dataApiKeydownHandler(t){const e=/input|textarea/i.test(t.target.tagName),i="Escape"===t.key,n=[Ke,Qe].includes(t.key);if(!n&&!i)return;if(e&&!i)return;t.preventDefault();const s=Q.findOne(Ge,t.delegateTarget.parentNode),o=li.getOrCreateInstance(s);if(n)return t.stopPropagation(),o.show(),void o._selectMenuItem(t);o._isShown()&&(t.stopPropagation(),o.hide(),s.focus())}}P.on(document,Ye,Ge,li.dataApiKeydownHandler),P.on(document,Ye,Ze,li.dataApiKeydownHandler),P.on(document,Xe,li.clearMenus),P.on(document,"keyup.bs.dropdown.data-api",li.clearMenus),P.on(document,Xe,Ge,(function(t){t.preventDefault(),li.getOrCreateInstance(this).toggle()})),g(li);const ci=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",hi=".sticky-top",di="padding-right",ui="margin-right";class fi{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,di,(e=>e+t)),this._setElementAttributes(ci,di,(e=>e+t)),this._setElementAttributes(hi,ui,(e=>e-t))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,di),this._resetElementAttributes(ci,di),this._resetElementAttributes(hi,ui)}isOverflowing(){return this.getWidth()>0}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t).getPropertyValue(e);t.style.setProperty(e,`${i(Number.parseFloat(s))}px`)}))}_saveInitialAttribute(t,e){const i=t.style.getPropertyValue(e);i&&B.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=B.getDataAttribute(t,e);null!==i?(B.removeDataAttribute(t,e),t.style.setProperty(e,i)):t.style.removeProperty(e)}))}_applyManipulationCallback(t,e){if(o(t))e(t);else for(const i of Q.find(t,this._element))e(i)}}const pi="show",gi="mousedown.bs.backdrop",mi={className:"modal-backdrop",clickCallback:null,isAnimated:!1,isVisible:!0,rootElement:"body"},_i={className:"string",clickCallback:"(function|null)",isAnimated:"boolean",isVisible:"boolean",rootElement:"(element|string)"};class bi extends F{constructor(t){super(),this._config=this._getConfig(t),this._isAppended=!1,this._element=null}static get Default(){return mi}static get DefaultType(){return _i}static get NAME(){return"backdrop"}show(t){if(!this._config.isVisible)return void m(t);this._append();const e=this._getElement();this._config.isAnimated&&d(e),e.classList.add(pi),this._emulateAnimation((()=>{m(t)}))}hide(t){this._config.isVisible?(this._getElement().classList.remove(pi),this._emulateAnimation((()=>{this.dispose(),m(t)}))):m(t)}dispose(){this._isAppended&&(P.off(this._element,gi),this._element.remove(),this._isAppended=!1)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_configAfterMerge(t){return t.rootElement=r(t.rootElement),t}_append(){if(this._isAppended)return;const t=this._getElement();this._config.rootElement.append(t),P.on(t,gi,(()=>{m(this._config.clickCallback)})),this._isAppended=!0}_emulateAnimation(t){_(t,this._getElement(),this._config.isAnimated)}}const vi=".bs.focustrap",yi="backward",wi={autofocus:!0,trapElement:null},Ai={autofocus:"boolean",trapElement:"element"};class Ei extends F{constructor(t){super(),this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}static get Default(){return wi}static get DefaultType(){return Ai}static get NAME(){return"focustrap"}activate(){this._isActive||(this._config.autofocus&&this._config.trapElement.focus(),P.off(document,vi),P.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),P.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,P.off(document,vi))}_handleFocusin(t){const{trapElement:e}=this._config;if(t.target===document||t.target===e||e.contains(t.target))return;const i=Q.focusableChildren(e);0===i.length?e.focus():this._lastTabNavDirection===yi?i[i.length-1].focus():i[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?yi:"forward")}}const Ti="hidden.bs.modal",Ci="show.bs.modal",Oi="modal-open",xi="show",ki="modal-static",Li={backdrop:!0,focus:!0,keyboard:!0},Di={backdrop:"(boolean|string)",focus:"boolean",keyboard:"boolean"};class Si extends z{constructor(t,e){super(t,e),this._dialog=Q.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._isTransitioning=!1,this._scrollBar=new fi,this._addEventListeners()}static get Default(){return Li}static get DefaultType(){return Di}static get NAME(){return"modal"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||P.trigger(this._element,Ci,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isTransitioning=!0,this._scrollBar.hide(),document.body.classList.add(Oi),this._adjustDialog(),this._backdrop.show((()=>this._showElement(t))))}hide(){this._isShown&&!this._isTransitioning&&(P.trigger(this._element,"hide.bs.modal").defaultPrevented||(this._isShown=!1,this._isTransitioning=!0,this._focustrap.deactivate(),this._element.classList.remove(xi),this._queueCallback((()=>this._hideModal()),this._element,this._isAnimated())))}dispose(){for(const t of[window,this._dialog])P.off(t,".bs.modal");this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ei({trapElement:this._element})}_showElement(t){document.body.contains(this._element)||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0;const e=Q.findOne(".modal-body",this._dialog);e&&(e.scrollTop=0),d(this._element),this._element.classList.add(xi),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,P.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,this._isAnimated())}_addEventListeners(){P.on(this._element,"keydown.dismiss.bs.modal",(t=>{if("Escape"===t.key)return this._config.keyboard?(t.preventDefault(),void this.hide()):void this._triggerBackdropTransition()})),P.on(window,"resize.bs.modal",(()=>{this._isShown&&!this._isTransitioning&&this._adjustDialog()})),P.on(this._element,"mousedown.dismiss.bs.modal",(t=>{t.target===t.currentTarget&&("static"!==this._config.backdrop?this._config.backdrop&&this.hide():this._triggerBackdropTransition())}))}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Oi),this._resetAdjustments(),this._scrollBar.reset(),P.trigger(this._element,Ti)}))}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(P.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._element.style.overflowY;"hidden"===e||this._element.classList.contains(ki)||(t||(this._element.style.overflowY="hidden"),this._element.classList.add(ki),this._queueCallback((()=>{this._element.classList.remove(ki),this._queueCallback((()=>{this._element.style.overflowY=e}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;if(i&&!t){const t=p()?"paddingLeft":"paddingRight";this._element.style[t]=`${e}px`}if(!i&&t){const t=p()?"paddingRight":"paddingLeft";this._element.style[t]=`${e}px`}}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Si.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}P.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),P.one(e,Ci,(t=>{t.defaultPrevented||P.one(e,Ti,(()=>{a(this)&&this.focus()}))}));const i=Q.findOne(".modal.show");i&&Si.getInstance(i).hide(),Si.getOrCreateInstance(e).toggle(this)})),R(Si),g(Si);const Ii="show",Ni="showing",Pi="hiding",ji=".offcanvas.show",Mi="hidePrevented.bs.offcanvas",Hi="hidden.bs.offcanvas",$i={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"(boolean|string)",keyboard:"boolean",scroll:"boolean"};class Bi extends z{constructor(t,e){super(t,e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get Default(){return $i}static get DefaultType(){return Wi}static get NAME(){return"offcanvas"}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||P.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add(Ni),this._queueCallback((()=>{this._config.scroll&&!this._config.backdrop||this._focustrap.activate(),this._element.classList.add(Ii),this._element.classList.remove(Ni),P.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(P.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.add(Pi),this._backdrop.hide(),this._queueCallback((()=>{this._element.classList.remove(Ii,Pi),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._config.scroll||(new fi).reset(),P.trigger(this._element,Hi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_initializeBackDrop(){const t=Boolean(this._config.backdrop);return new bi({className:"offcanvas-backdrop",isVisible:t,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:t?()=>{"static"!==this._config.backdrop?this.hide():P.trigger(this._element,Mi)}:null})}_initializeFocusTrap(){return new Ei({trapElement:this._element})}_addEventListeners(){P.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{"Escape"===t.key&&(this._config.keyboard?this.hide():P.trigger(this._element,Mi))}))}static jQueryInterface(t){return this.each((function(){const e=Bi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}P.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this))return;P.one(e,Hi,(()=>{a(this)&&this.focus()}));const i=Q.findOne(ji);i&&i!==e&&Bi.getInstance(i).hide(),Bi.getOrCreateInstance(e).toggle(this)})),P.on(window,"load.bs.offcanvas.data-api",(()=>{for(const t of Q.find(ji))Bi.getOrCreateInstance(t).show()})),P.on(window,"resize.bs.offcanvas",(()=>{for(const t of Q.find("[aria-modal][class*=show][class*=offcanvas-]"))"fixed"!==getComputedStyle(t).position&&Bi.getOrCreateInstance(t).hide()})),R(Bi),g(Bi);const Fi=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),zi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ri=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,qi=(t,e)=>{const i=t.nodeName.toLowerCase();return e.includes(i)?!Fi.has(i)||Boolean(zi.test(t.nodeValue)||Ri.test(t.nodeValue)):e.filter((t=>t instanceof RegExp)).some((t=>t.test(i)))},Vi={"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},Ki={allowList:Vi,content:{},extraClass:"",html:!1,sanitize:!0,sanitizeFn:null,template:"
"},Qi={allowList:"object",content:"object",extraClass:"(string|function)",html:"boolean",sanitize:"boolean",sanitizeFn:"(null|function)",template:"string"},Xi={entry:"(string|element|function|null)",selector:"(string|element)"};class Yi extends F{constructor(t){super(),this._config=this._getConfig(t)}static get Default(){return Ki}static get DefaultType(){return Qi}static get NAME(){return"TemplateFactory"}getContent(){return Object.values(this._config.content).map((t=>this._resolvePossibleFunction(t))).filter(Boolean)}hasContent(){return this.getContent().length>0}changeContent(t){return this._checkContent(t),this._config.content={...this._config.content,...t},this}toHtml(){const t=document.createElement("div");t.innerHTML=this._maybeSanitize(this._config.template);for(const[e,i]of Object.entries(this._config.content))this._setContent(t,i,e);const e=t.children[0],i=this._resolvePossibleFunction(this._config.extraClass);return i&&e.classList.add(...i.split(" ")),e}_typeCheckConfig(t){super._typeCheckConfig(t),this._checkContent(t.content)}_checkContent(t){for(const[e,i]of Object.entries(t))super._typeCheckConfig({selector:e,entry:i},Xi)}_setContent(t,e,i){const n=Q.findOne(i,t);n&&((e=this._resolvePossibleFunction(e))?o(e)?this._putElementInTemplate(r(e),n):this._config.html?n.innerHTML=this._maybeSanitize(e):n.textContent=e:n.remove())}_maybeSanitize(t){return this._config.sanitize?function(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(const t of s){const i=t.nodeName.toLowerCase();if(!Object.keys(e).includes(i)){t.remove();continue}const n=[].concat(...t.attributes),s=[].concat(e["*"]||[],e[i]||[]);for(const e of n)qi(e,s)||t.removeAttribute(e.nodeName)}return n.body.innerHTML}(t,this._config.allowList,this._config.sanitizeFn):t}_resolvePossibleFunction(t){return"function"==typeof t?t(this):t}_putElementInTemplate(t,e){if(this._config.html)return e.innerHTML="",void e.append(t);e.textContent=t.textContent}}const Ui=new Set(["sanitize","allowList","sanitizeFn"]),Gi="fade",Ji="show",Zi=".modal",tn="hide.bs.modal",en="hover",nn="focus",sn={AUTO:"auto",TOP:"top",RIGHT:p()?"left":"right",BOTTOM:"bottom",LEFT:p()?"right":"left"},on={allowList:Vi,animation:!0,boundary:"clippingParents",container:!1,customClass:"",delay:0,fallbackPlacements:["top","right","bottom","left"],html:!1,offset:[0,0],placement:"top",popperConfig:null,sanitize:!0,sanitizeFn:null,selector:!1,template:'',title:"",trigger:"hover focus"},rn={allowList:"object",animation:"boolean",boundary:"(string|element)",container:"(string|element|boolean)",customClass:"(string|function)",delay:"(number|object)",fallbackPlacements:"array",html:"boolean",offset:"(array|string|function)",placement:"(string|function)",popperConfig:"(null|object|function)",sanitize:"boolean",sanitizeFn:"(null|function)",selector:"(string|boolean)",template:"string",title:"(string|element|function)",trigger:"string"};class an extends z{constructor(t,e){if(void 0===qe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t,e),this._isEnabled=!0,this._timeout=0,this._isHovered=!1,this._activeTrigger={},this._popper=null,this._templateFactory=null,this._newContent=null,this.tip=null,this._setListeners()}static get Default(){return on}static get DefaultType(){return rn}static get NAME(){return"tooltip"}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled){if(t){const e=this._initializeOnDelegatedTarget(t);return e._activeTrigger.click=!e._activeTrigger.click,void(e._isWithActiveTrigger()?e._enter():e._leave())}this._isShown()?this._leave():this._enter()}}dispose(){clearTimeout(this._timeout),P.off(this._element.closest(Zi),tn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this._isWithContent()||!this._isEnabled)return;const t=P.trigger(this._element,this.constructor.eventName("show")),e=(c(this._element)||this._element.ownerDocument.documentElement).contains(this._element);if(t.defaultPrevented||!e)return;this.tip&&(this.tip.remove(),this.tip=null);const i=this._getTipElement();this._element.setAttribute("aria-describedby",i.getAttribute("id"));const{container:n}=this._config;if(this._element.ownerDocument.documentElement.contains(this.tip)||(n.append(i),P.trigger(this._element,this.constructor.eventName("inserted"))),this._popper?this._popper.update():this._popper=this._createPopper(i),i.classList.add(Ji),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))P.on(t,"mouseover",h);this._queueCallback((()=>{const t=this._isHovered;this._isHovered=!1,P.trigger(this._element,this.constructor.eventName("shown")),t&&this._leave()}),this.tip,this._isAnimated())}hide(){if(!this._isShown())return;if(P.trigger(this._element,this.constructor.eventName("hide")).defaultPrevented)return;const t=this._getTipElement();if(t.classList.remove(Ji),"ontouchstart"in document.documentElement)for(const t of[].concat(...document.body.children))P.off(t,"mouseover",h);this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1,this._isHovered=!1,this._queueCallback((()=>{this._isWithActiveTrigger()||(this._isHovered||t.remove(),this._element.removeAttribute("aria-describedby"),P.trigger(this._element,this.constructor.eventName("hidden")),this._disposePopper())}),this.tip,this._isAnimated())}update(){this._popper&&this._popper.update()}_isWithContent(){return Boolean(this._getTitle())}_getTipElement(){return this.tip||(this.tip=this._createTipElement(this._newContent||this._getContentForTemplate())),this.tip}_createTipElement(t){const e=this._getTemplateFactory(t).toHtml();if(!e)return null;e.classList.remove(Gi,Ji),e.classList.add(`bs-${this.constructor.NAME}-auto`);const i=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME).toString();return e.setAttribute("id",i),this._isAnimated()&&e.classList.add(Gi),e}setContent(t){this._newContent=t,this._isShown()&&(this._disposePopper(),this.show())}_getTemplateFactory(t){return this._templateFactory?this._templateFactory.changeContent(t):this._templateFactory=new Yi({...this._config,content:t,extraClass:this._resolvePossibleFunction(this._config.customClass)}),this._templateFactory}_getContentForTemplate(){return{".tooltip-inner":this._getTitle()}}_getTitle(){return this._resolvePossibleFunction(this._config.title)||this._config.originalTitle}_initializeOnDelegatedTarget(t){return this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_isAnimated(){return this._config.animation||this.tip&&this.tip.classList.contains(Gi)}_isShown(){return this.tip&&this.tip.classList.contains(Ji)}_createPopper(t){const e="function"==typeof this._config.placement?this._config.placement.call(this,t,this._element):this._config.placement,i=sn[e.toUpperCase()];return Re(this._element,t,this._getPopperConfig(i))}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"preSetPlacement",enabled:!0,phase:"beforeMain",fn:t=>{this._getTipElement().setAttribute("data-popper-placement",t.state.placement)}}]};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_setListeners(){const t=this._config.trigger.split(" ");for(const e of t)if("click"===e)P.on(this._element,this.constructor.eventName("click"),this._config.selector,(t=>this.toggle(t)));else if("manual"!==e){const t=e===en?this.constructor.eventName("mouseenter"):this.constructor.eventName("focusin"),i=e===en?this.constructor.eventName("mouseleave"):this.constructor.eventName("focusout");P.on(this._element,t,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusin"===t.type?nn:en]=!0,e._enter()})),P.on(this._element,i,this._config.selector,(t=>{const e=this._initializeOnDelegatedTarget(t);e._activeTrigger["focusout"===t.type?nn:en]=e._element.contains(t.relatedTarget),e._leave()}))}this._hideModalHandler=()=>{this._element&&this.hide()},P.on(this._element.closest(Zi),tn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._config.originalTitle;t&&(this._element.getAttribute("aria-label")||this._element.textContent.trim()||this._element.setAttribute("aria-label",t),this._element.removeAttribute("title"))}_enter(){this._isShown()||this._isHovered?this._isHovered=!0:(this._isHovered=!0,this._setTimeout((()=>{this._isHovered&&this.show()}),this._config.delay.show))}_leave(){this._isWithActiveTrigger()||(this._isHovered=!1,this._setTimeout((()=>{this._isHovered||this.hide()}),this._config.delay.hide))}_setTimeout(t,e){clearTimeout(this._timeout),this._timeout=setTimeout(t,e)}_isWithActiveTrigger(){return Object.values(this._activeTrigger).includes(!0)}_getConfig(t){const e=B.getDataAttributes(this._element);for(const t of Object.keys(e))Ui.has(t)&&delete e[t];return t={...e,..."object"==typeof t&&t?t:{}},t=this._mergeConfigObj(t),t=this._configAfterMerge(t),this._typeCheckConfig(t),t}_configAfterMerge(t){return t.container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),t.originalTitle=this._element.getAttribute("title")||"","number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=an.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(an);const ln={...an.Default,content:"",offset:[0,8],placement:"right",template:'',trigger:"click"},cn={...an.DefaultType,content:"(null|string|element|function)"};class hn extends an{static get Default(){return ln}static get DefaultType(){return cn}static get NAME(){return"popover"}_isWithContent(){return this._getTitle()||this._getContent()}_getContentForTemplate(){return{".popover-header":this._getTitle(),".popover-body":this._getContent()}}_getContent(){return this._resolvePossibleFunction(this._config.content)}static jQueryInterface(t){return this.each((function(){const e=hn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(hn);const dn="click.bs.scrollspy",un="active",fn="[href]",pn={offset:null,rootMargin:"0px 0px -25%",smoothScroll:!1,target:null},gn={offset:"(number|null)",rootMargin:"string",smoothScroll:"boolean",target:"element"};class mn extends z{constructor(t,e){super(t,e),this._targetLinks=new Map,this._observableSections=new Map,this._rootElement="visible"===getComputedStyle(this._element).overflowY?null:this._element,this._activeTarget=null,this._observer=null,this._previousScrollData={visibleEntryTop:0,parentScrollTop:0},this.refresh()}static get Default(){return pn}static get DefaultType(){return gn}static get NAME(){return"scrollspy"}refresh(){this._initializeTargetsAndObservables(),this._maybeEnableSmoothScroll(),this._observer?this._observer.disconnect():this._observer=this._getNewObserver();for(const t of this._observableSections.values())this._observer.observe(t)}dispose(){this._observer.disconnect(),super.dispose()}_configAfterMerge(t){return t.target=r(t.target)||document.body,t}_maybeEnableSmoothScroll(){this._config.smoothScroll&&(P.off(this._config.target,dn),P.on(this._config.target,dn,fn,(t=>{const e=this._observableSections.get(t.target.hash);if(e){t.preventDefault();const i=this._rootElement||window,n=e.offsetTop-this._element.offsetTop;if(i.scrollTo)return void i.scrollTo({top:n,behavior:"smooth"});i.scrollTop=n}})))}_getNewObserver(){const t={root:this._rootElement,threshold:[.1,.5,1],rootMargin:this._getRootMargin()};return new IntersectionObserver((t=>this._observerCallback(t)),t)}_observerCallback(t){const e=t=>this._targetLinks.get(`#${t.target.id}`),i=t=>{this._previousScrollData.visibleEntryTop=t.target.offsetTop,this._process(e(t))},n=(this._rootElement||document.documentElement).scrollTop,s=n>=this._previousScrollData.parentScrollTop;this._previousScrollData.parentScrollTop=n;for(const o of t){if(!o.isIntersecting){this._activeTarget=null,this._clearActiveClass(e(o));continue}const t=o.target.offsetTop>=this._previousScrollData.visibleEntryTop;if(s&&t){if(i(o),!n)return}else s||t||i(o)}}_getRootMargin(){return this._config.offset?`${this._config.offset}px 0px -30%`:this._config.rootMargin}_initializeTargetsAndObservables(){this._targetLinks=new Map,this._observableSections=new Map;const t=Q.find(fn,this._config.target);for(const e of t){if(!e.hash||l(e))continue;const t=Q.findOne(e.hash,this._element);a(t)&&(this._targetLinks.set(e.hash,e),this._observableSections.set(e.hash,t))}}_process(t){this._activeTarget!==t&&(this._clearActiveClass(this._config.target),this._activeTarget=t,t.classList.add(un),this._activateParents(t),P.trigger(this._element,"activate.bs.scrollspy",{relatedTarget:t}))}_activateParents(t){if(t.classList.contains("dropdown-item"))Q.findOne(".dropdown-toggle",t.closest(".dropdown")).classList.add(un);else for(const e of Q.parents(t,".nav, .list-group"))for(const t of Q.prev(e,".nav-link, .nav-item > .nav-link, .list-group-item"))t.classList.add(un)}_clearActiveClass(t){t.classList.remove(un);const e=Q.find("[href].active",t);for(const t of e)t.classList.remove(un)}static jQueryInterface(t){return this.each((function(){const e=mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}P.on(window,"load.bs.scrollspy.data-api",(()=>{for(const t of Q.find('[data-bs-spy="scroll"]'))mn.getOrCreateInstance(t)})),g(mn);const _n="ArrowLeft",bn="ArrowRight",vn="ArrowUp",yn="ArrowDown",wn="active",An="fade",En="show",Tn='[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',Cn=`.nav-link:not(.dropdown-toggle), .list-group-item:not(.dropdown-toggle), [role="tab"]:not(.dropdown-toggle), ${Tn}`;class On extends z{constructor(t){super(t),this._parent=this._element.closest('.list-group, .nav, [role="tablist"]'),this._parent&&(this._setInitialAttributes(this._parent,this._getChildren()),P.on(this._element,"keydown.bs.tab",(t=>this._keydown(t))))}static get NAME(){return"tab"}show(){const t=this._element;if(this._elemIsActive(t))return;const e=this._getActiveElem(),i=e?P.trigger(e,"hide.bs.tab",{relatedTarget:t}):null;P.trigger(t,"show.bs.tab",{relatedTarget:e}).defaultPrevented||i&&i.defaultPrevented||(this._deactivate(e,t),this._activate(t,e))}_activate(t,e){t&&(t.classList.add(wn),this._activate(n(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.focus(),t.removeAttribute("tabindex"),t.setAttribute("aria-selected",!0),this._toggleDropDown(t,!0),P.trigger(t,"shown.bs.tab",{relatedTarget:e})):t.classList.add(En)}),t,t.classList.contains(An)))}_deactivate(t,e){t&&(t.classList.remove(wn),t.blur(),this._deactivate(n(t)),this._queueCallback((()=>{"tab"===t.getAttribute("role")?(t.setAttribute("aria-selected",!1),t.setAttribute("tabindex","-1"),this._toggleDropDown(t,!1),P.trigger(t,"hidden.bs.tab",{relatedTarget:e})):t.classList.remove(En)}),t,t.classList.contains(An)))}_keydown(t){if(![_n,bn,vn,yn].includes(t.key))return;t.stopPropagation(),t.preventDefault();const e=[bn,yn].includes(t.key),i=b(this._getChildren().filter((t=>!l(t))),t.target,e,!0);i&&On.getOrCreateInstance(i).show()}_getChildren(){return Q.find(Cn,this._parent)}_getActiveElem(){return this._getChildren().find((t=>this._elemIsActive(t)))||null}_setInitialAttributes(t,e){this._setAttributeIfNotExists(t,"role","tablist");for(const t of e)this._setInitialAttributesOnChild(t)}_setInitialAttributesOnChild(t){t=this._getInnerElement(t);const e=this._elemIsActive(t),i=this._getOuterElement(t);t.setAttribute("aria-selected",e),i!==t&&this._setAttributeIfNotExists(i,"role","presentation"),e||t.setAttribute("tabindex","-1"),this._setAttributeIfNotExists(t,"role","tab"),this._setInitialAttributesOnTargetPanel(t)}_setInitialAttributesOnTargetPanel(t){const e=n(t);e&&(this._setAttributeIfNotExists(e,"role","tabpanel"),t.id&&this._setAttributeIfNotExists(e,"aria-labelledby",`#${t.id}`))}_toggleDropDown(t,e){const i=this._getOuterElement(t);if(!i.classList.contains("dropdown"))return;const n=(t,n)=>{const s=Q.findOne(t,i);s&&s.classList.toggle(n,e)};n(".dropdown-toggle",wn),n(".dropdown-menu",En),n(".dropdown-item",wn),i.setAttribute("aria-expanded",e)}_setAttributeIfNotExists(t,e,i){t.hasAttribute(e)||t.setAttribute(e,i)}_elemIsActive(t){return t.classList.contains(wn)}_getInnerElement(t){return t.matches(Cn)?t:Q.findOne(Cn,t)}_getOuterElement(t){return t.closest(".nav-item, .list-group-item")||t}static jQueryInterface(t){return this.each((function(){const e=On.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t]()}}))}}P.on(document,"click.bs.tab",Tn,(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),l(this)||On.getOrCreateInstance(this).show()})),P.on(window,"load.bs.tab",(()=>{for(const t of Q.find('.active[data-bs-toggle="tab"], .active[data-bs-toggle="pill"], .active[data-bs-toggle="list"]'))On.getOrCreateInstance(t)})),g(On);const xn="hide",kn="show",Ln="showing",Dn={animation:"boolean",autohide:"boolean",delay:"number"},Sn={animation:!0,autohide:!0,delay:5e3};class In extends z{constructor(t,e){super(t,e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get Default(){return Sn}static get DefaultType(){return Dn}static get NAME(){return"toast"}show(){P.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(xn),d(this._element),this._element.classList.add(kn,Ln),this._queueCallback((()=>{this._element.classList.remove(Ln),P.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this.isShown()&&(P.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(Ln),this._queueCallback((()=>{this._element.classList.add(xn),this._element.classList.remove(Ln,kn),P.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this.isShown()&&this._element.classList.remove(kn),super.dispose()}isShown(){return this._element.classList.contains(kn)}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){P.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),P.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),P.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),P.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=In.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(In),g(In),{Alert:q,Button:K,Carousel:at,Collapse:pt,Dropdown:li,Modal:Si,Offcanvas:Bi,Popover:hn,ScrollSpy:mn,Tab:On,Toast:In,Tooltip:an}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map + +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0F[s]["max"+e])throw new Error("Value for min"+e+" can not be greater than max"+e)}s in F&&"iFrameResizer"in i?N(s,"Ignored iFrame, already setup."):(o(e),function(){switch(T(s,"IFrame scrolling "+(F[s]&&F[s].scrolling?"enabled":"disabled")+" for "+s),i.style.overflow=!1===(F[s]&&F[s].scrolling)?"hidden":"auto",F[s]&&F[s].scrolling){case"omit":break;case!0:i.scrolling="yes";break;case!1:i.scrolling="no";break;default:i.scrolling=F[s]?F[s].scrolling:"no"}}(),c("Height"),c("Width"),d("maxHeight"),d("minHeight"),d("maxWidth"),d("minWidth"),"number"!=typeof(F[s]&&F[s].bodyMargin)&&"0"!==(F[s]&&F[s].bodyMargin)||(F[s].bodyMarginV1=F[s].bodyMargin,F[s].bodyMargin=F[s].bodyMargin+"px"),n(q(s)),F[s]&&(F[s].iframe.iFrameResizer={close:C.bind(null,F[s].iframe),removeListeners:p.bind(null,F[s].iframe),resize:B.bind(null,"Window resize","resize",F[s].iframe),moveToAnchor:function(e){B("Move to anchor","moveToAnchor:"+e,F[s].iframe,s)},sendMessage:function(e){B("Send Message","message:"+(e=JSON.stringify(e)),F[s].iframe,s)}}))}function c(e,n){null===t&&(t=setTimeout(function(){t=null,e()},n))}function n(){"hidden"!==document.visibilityState&&(T("document","Trigger event: Visiblity change"),c(function(){w("Tab Visable","resize")},16))}function w(t,i){Object.keys(F).forEach(function(e){var n;F[n=e]&&"parent"===F[n].resizeFrom&&F[n].autoResize&&!F[n].firstRun&&B(t,i,F[e].iframe,e)})}function b(){O(window,"message",e),O(window,"resize",function(){var e;T("window","Trigger event: "+(e="resize")),c(function(){w("Window "+e,"resize")},16)}),O(document,"visibilitychange",n),O(document,"-webkit-visibilitychange",n)}function y(){function i(e,n){n&&(function(){if(!n.tagName)throw new TypeError("Object is not a valid DOM element");if("IFRAME"!==n.tagName.toUpperCase())throw new TypeError("Expected