commit fabffc562b9fea0888afdb033a6fd00cf19b8196 Author: kiu Date: Tue Sep 24 21:49:13 2024 +0200 V1 diff --git a/README.md b/README.md new file mode 100644 index 0000000..af1db8d --- /dev/null +++ b/README.md @@ -0,0 +1,10 @@ +# doli_install +Dolibarr installation or upgrade php script + +Make the installation or upgrade much more easier ! + +1. Download the PHP script +2. Upload it in the directory where you want to install dolibarr (htdocs) +3. Run the script with your Web browser + +Enjoy! diff --git a/doli_install.php b/doli_install.php new file mode 100644 index 0000000..b7a6ebf --- /dev/null +++ b/doli_install.php @@ -0,0 +1,1233 @@ + "Installation ou Mise à jour de Dolibarr", + "NextStep" => "Étape Suivante", + "SelectLanguage" => "Sélection de la langue", + "DefaultLanguage" => "Langue par défaut", + "Check" => "Vérifications", + "MiscellaneousChecks" => "Vérification des prérequis", + "PHPVersion" => "Version PHP", + "ErrorPHPVersionTooLow" => "Version de PHP trop ancienne. PHP 5.5 Minimum requise. Votre Version PHP est", + "ErrorPHPDoesNotSupportCurl" => "Votre version de PHP ne supporte pas l'extension Curl.", + "ErrorPHPDoesNotSupportZip" => "Votre version de PHP ne supporte pas l'extension Zip.", + "PHPSupportCurl" => "PHP supporte l'extension Curl.", + "PHPSupportZip" => "PHP supporte l'extension Zip.", + "PHPMemoryOK" => "Votre mémoire maximum de session PHP est définie à", + "PHPMemoryTooLow" => "Votre mémoire maximum de session PHP est trop faible. Il est recommandé de modifier le paramètre memory_limit de votre fichier php.ini à au moins 64M octets. Elle est pour le moment définie à", + "ErrorDocRootNotWrit" => "Le répertoire d'installation ne peut être écrit", + "DocRootWrit" => "Le répertoire d'installation peut être écrit", + "UpgradeDetected" => "Un fichier conf.php a été trouvé : Mise à jour de Dolibarr . Version détecté", + "IntallNewDetected" => "Aucun fichier conf.php n'a été trouvé : Installation Neuve de Dolibarr .", + "ChooseVersion" => "Choisir la version à installer", + "Download" => "Téléchargement", + "ErrorNoVersionSelectec" => "Vous n'avez pas sélectionné de version.", + "UrlDownload" => "Adresse de téléchargement", + "ErrorDuringDownload" => "Erreur pendant le téléchargement", + "DownloadPackage" => "Téléchargement du package Dolibarr Version", + "DownloadProgress" => "Progression du téléchargement", + "DownloadCompleted" => "Téléchargement terminé. Taille du package", + "ErrorDownloadFile" => "Le fichier téléchargé n'est pas une archive !", + "Install" => "Installer la version téléchargée", + "FileIsAZip" => "Le fichier téléchargé est bien un zip", + "ErrorNotAZip" => "Le fichier téléchargé n'est pas un zip", + "NumbersOfDirectories" => "Nombre de dossiers crées", + "NumbersOfFiles" => "Nombre de fichiers crées", + "NoErrors" => "Aucune erreur lors de l'extraction", + "SomeErrors" => "Quelques erreurs lors de l'extraction. Nombre d'erreurs", + "RedirectToInstall" => "L'installation ou mise à jour est maintenant terminée. En cliquant sur \"Suivant\" vous allez être redirigé vers l'installation de Dolibarr", + "InstallLockDeleted" => "Le fichier install.lock a été trouvé et supprimé", + "InstallLockNotFounded" => "Aucun fichier install.lock n'a été trouvé. Si il existe vous devez le supprimer manuellement", + "InstallLockFoundNoDeleted" => "Le fichier install.lock existe mais n'a pas pu être supprimé", + "DeleteScript" => "Supprimer ce script php du serveur (Recommandé)", + "DeleteLog" => "Supprimer le fichier log de ce script (Recommandé)", + "AFewAdditionalOptions" => "Quelques options supplémentaires", + "From" => "depuis" + ); + }else{ + $lang_array = array( + "DolibarrSetup" => "Dolibarr Install or Upgrade", + "NextStep" => "Next Step", + "SelectLanguage" => "Language selection", + "DefaultLanguage" => "Default language", + "Check" => "Initial Checks", + "MiscellaneousChecks" => "Prerequisites check", + "PHPVersion" => "PHP Version", + "ErrorPHPVersionTooLow" => "PHP version too old. PHP 5.5 Minimum is required. Your PHP Version is", + "ErrorPHPDoesNotSupportCurl" => "Your PHP installation does not support Curl.", + "PHPSupportCurl" => "This PHP supports Curl.", + "ErrorPHPDoesNotSupportZip" => "Your PHP installation does not support Zip.", + "PHPSupportZip" => "This PHP supports Zip.", + "PHPMemoryOK" => "Your PHP max session memory is set to", + "PHPMemoryTooLow" => "Your maximum PHP session memory is too low. It is recommended to change the memory_limit parameter of your php.ini file to at least 64M bytes. It is currently set to", + "ErrorDocRootNotWrit" => "The installation directory is not writtable", + "DocRootWrit" => "The installation directory is writtable", + "UpgradeDetected" => "A conf.php file has been found: Dolibar update . Version detected", + "IntallNewDetected" => "No conf.php file was found : New installation of Dolibar .", + "ChooseVersion" => "Choose the version to be installed", + "Download" => "Download", + "ErrorNoVersionSelectec" => "No versions has been selected.", + "UrlDownload" => "Download URL", + "ErrorDuringDownload" => "Error during Download", + "DownloadPackage" => "Download Dolibarr package Version", + "DownloadProgress" => "Download Progress", + "DownloadCompleted" => "Download completed. Package size", + "ErrorDownloadFile" => "The downloaded package is not a zip file !", + "Install" => "Install the downloaded version", + "FileIsAZip" => "The downloaded file is a zip", + "ErrorNotAZip" => "The downloaded file is not a zip", + "NumbersOfDirectories" => "Numbers of directories created", + "NumbersOfFiles" => "Numbers of files created", + "NoErrors" => "No error during extraction", + "SomeErrors" => "Some errors during extractions. Errors numbers", + "RedirectToInstall" => "The Dolibarr new install or update is now over. When you will click on \"Next\" you will be redirected to dolibarr installation script", + "InstallLockDeleted" => "The install.lock files has been found and removed", + "InstallLockNotFounded" => "No install.lock file has been found. If it exist, you have to remove it manualy", + "InstallLockFoundNoDeleted" => "The install.lock file exist but not possible to delete it", + "DeleteScript" => "Delete this php script from the server (Recommended)", + "DeleteLog" => "Delete the log file of this script (Recommended)", + "AFewAdditionalOptions" => "A few additional options", + "From" => "from" + ); + } + return $lang_array; +} + +/** + * Show HTML header of install pages + * + * @param string $subtitle Title + * @param string $action Action code + * @param array $langs Language + * @return void + */ +function pHeader($subtitle, $action = '', $langs = ''){ + + // We force the content charset + header("Content-type: text/html; charset=utf-8"); + header("X-Content-Type-Options: nosniff"); + + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + print ''."\n"; + + print ''.$langs["DolibarrSetup"].''."\n"; + print ''."\n"; + + print ''."\n"; + + print '
'; + print 'Dolibarr logo
'; + print SCRIPT_VERSION; + print '

'; + + print ''.$langs["DolibarrSetup"]; + if ($subtitle) { + print ' - '.$subtitle; + } + print ''."\n"; + + print '
'."\n"; + print ''."\n"; + + print '
'."\n"; + + print '
'."\n"; +} + +/** + * Print HTML footer of install pages + * + * @param integer $nonext 1=No button "Next step" + * @param array $langs Language array + * @param string $selectlang Language code + * @return void + */ +function pFooter($nonext = 0, $langs = '', $selectlang = ''){ + + print '
'."\n"; + print '
'."\n"; + + if (! $nonext){ + print '
'; + print '">
'; + } + if ($selectlang) + { + print ''; + } + + print '
'."\n"; + print ''."\n"; + print ''."\n"; +} + +/** + * Return image relative URL + * + * @param string $image Image tag + * @return string Relative URL of the image + */ +function url_img($image){ + return $_SERVER["PHP_SELF"].'?action=img&file='.$image ; +} + +function get_sourceforge_files($url){ + + $context = stream_context_create(array('http' => array('header' => 'Accept: application/xml'))); + $xml = file_get_contents($url, false, $context); + $xml = simplexml_load_string($xml); + + $sourceforge_versions = array(); + foreach($xml->channel->item as $file){ + if (strstr($file->link,".zip")){ + preg_match ('/[0-9]+\.[0-9]+\.[0-9]+/', $file->link , $matches); + $sourceforge_versions[] = $matches[0]; + } + } + rsort($sourceforge_versions, SORT_NUMERIC ); + return $sourceforge_versions; +} + +/** + * CURL follow redirections event if open_basedir or safe_mode are ON + * + * @param resource $ch Curl Resource + * @param Int $maxredirect Max redirections + * @return curl_exec Execution of CURL + * Code from : https://www.php.net/manual/fr/function.curl-setopt.php#102121 + */ +function curl_exec_follow($ch, &$maxredirect = null) { + $mr = $maxredirect === null ? 5 : intval($maxredirect); + if (ini_get('open_basedir') == '' && ini_get('safe_mode' == 'Off')) { + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, $mr > 0); + curl_setopt($ch, CURLOPT_MAXREDIRS, $mr); + } else { + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, false); + if ($mr > 0) { + $newurl = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL); + + $rch = curl_copy_handle($ch); + curl_setopt($rch, CURLOPT_HEADER, true); + curl_setopt($rch, CURLOPT_NOBODY, true); + curl_setopt($rch, CURLOPT_FORBID_REUSE, false); + curl_setopt($rch, CURLOPT_RETURNTRANSFER, true); + do { + curl_setopt($rch, CURLOPT_URL, $newurl); + $header = curl_exec($rch); + if (curl_errno($rch)) { + $code = 0; + } else { + $code = curl_getinfo($rch, CURLINFO_HTTP_CODE); + if ($code == 301 || $code == 302) { + preg_match('/Location:(.*?)\n/i', $header, $matches); + $newurl = trim(array_pop($matches)); + write_log('New URL found '.$newurl); + } else { + $code = 0; + } + } + } while ($code && --$mr); + curl_close($rch); + if (!$mr) { + if ($maxredirect === null) { + write_log('Too many redirects'); + trigger_error('Too many redirects. When following redirects, libcurl hit the maximum amount.', E_USER_WARNING); + } else { + $maxredirect = 0; + } + return false; + } + curl_setopt($ch, CURLOPT_URL, $newurl); + } + } + return curl_exec($ch); +} + +/** + * CURL Progress function + * + * @param resource $ch Curl Resource + * @param Int $download_size Downloaded size + * @param Int $downloaded Downloaded + * @param Int $upload_size Uploaded size + * @param Int $uploaded Uploaded + * @return Nothing + * Code from : https://stackoverflow.com/questions/13958303/curl-download-progress-in-php + */ +function progress($resource,$download_size, $downloaded, $upload_size, $uploaded) +{ + static $previousProgress = 0; + + if ( $download_size == 0 ) { + //Github doesn't send the size, so estimated size + $progress = round($downloaded / 650000); + } else { + $progress = round($downloaded * 100 / $download_size); + } + + if ( $progress > $previousProgress) + { + $previousProgress = $progress; + //update JavaScript progress bar to show download progress + echo ''."\n"; + } +} + +/** + * Output Human file size + * + * @param Int $bytes Size in bytes + * @param Int $decimals Numbers of decimals + * @return String + * Code from : https://www.php.net/manual/fr/function.filesize.php#120250 + */ +function human_filesize($bytes, $decimals = 2) { + $factor = floor((strlen($bytes) - 1) / 3); + if ($factor > 0) $sz = 'KMGT'; + return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$sz[$factor - 1] . 'B'; +} + +/** + * Extend class ZipArchive for directory extraction + * + * Code from : https://www.php.net/manual/fr/ziparchive.extractto.php#116353 + */ +if (class_exists("ZipArchive")){ + class my_ZipArchive extends ZipArchive{ + public function extractSubdirTo($destination, $subdir){ + $errors = array(); + $nb_directories = 0; + $nb_files = 0; + + // Prepare dirs + $destination = str_replace(array("/", "\\"), DIRECTORY_SEPARATOR, $destination); + $subdir = str_replace(array("/", "\\"), "/", $subdir); + + if (substr($destination, mb_strlen(DIRECTORY_SEPARATOR, "UTF-8") * -1) != DIRECTORY_SEPARATOR) + $destination .= DIRECTORY_SEPARATOR; + + if (substr($subdir, -1) != "/") + $subdir .= "/"; + + // Extract files + for ($i = 0; $i < $this->numFiles; $i++){ + $filename = $this->getNameIndex($i); + + if (substr($filename, 0, mb_strlen($subdir, "UTF-8")) == $subdir){ + $relativePath = substr($filename, mb_strlen($subdir, "UTF-8")); + $relativePath = str_replace(array("/", "\\"), DIRECTORY_SEPARATOR, $relativePath); + + if (mb_strlen($relativePath, "UTF-8") > 0){ + // Directory + if (substr($filename, -1) == "/"){ + // New dir + if (!is_dir($destination . $relativePath)){ + if (!@mkdir($destination . $relativePath, 0755, true)){ + $errors[$i] = $filename; + }else{ + $nb_directories++; + } + } + }else{ + if (dirname($relativePath) != "."){ + if (!is_dir($destination . dirname($relativePath))){ + // New dir (for file) + @mkdir($destination . dirname($relativePath), 0755, true); + $nb_directories++; + } + } + + // New file + if (@file_put_contents($destination . $relativePath, $this->getFromIndex($i)) === false){ + $errors[$i] = $filename; + }else{ + $nb_files++; + } + } + } + } + } + return array( + "nb_directories" => $nb_directories, + "nb_files" => $nb_files, + "errors" => $errors ); + } + } +} + +/*********************************************************************** +* * +* Main * +* * +************************************************************************/ + +// initialize action variable +$action = (!empty($_GET['action'])) ? $_GET['action'] : ''; +write_log('Action = '.$action); + +// initialize lang table +if (!empty($_POST['selectlang'])){ + $selectlang = $_POST['selectlang']; + $langs = language($selectlang); +}else{ + $templang = substr($_SERVER['HTTP_ACCEPT_LANGUAGE'], 0, 2); + $selectlang = ''; + $langs = language($templang); +} + +//If conf.php exist, load the conf +if (file_exists($conffile)){ + include ($conffile); + // Just to define version DOL_VERSION + if (! defined('DOL_INC_FOR_VERSION_ERROR')) define('DOL_INC_FOR_VERSION_ERROR', '1'); + require_once './filefunc.inc.php'; + write_log('Conf file exits. Dolibarr version installed : '.DOL_VERSION); +}else{ + //we use the current folder to extract dolibarr + $dolibarr_main_document_root=__DIR__; + $dolibarr_main_data_root="../documents"; + write_log('Conf file doesn\'t exist'); +} + +//Index page +if ($action == ''){ + write_log('--- Enter in Index Page ---'); + pHeader($langs["SelectLanguage"], 'check', $langs); + echo '

'."\n"; + echo ''."\n"; + echo '
'."\n"; + echo $langs["DefaultLanguage"].':


'."\n"; + pFooter( 0, $langs, $selectlang); +} + +//Check page +if ($action == 'check'){ + write_log('--- Enter in Check Page ---'); + $checkfail = 0; + + pHeader($langs["Check"], 'download', $langs); + + print '

Database '.$langs["MiscellaneousChecks"]." :

\n"; + + //Check PHP version + if (version_compare(PHP_VERSION, '5.5.0') >= 0) { + print 'Ok '.$langs["PHPVersion"]." ".PHP_VERSION."
\n"; + }else{ + print 'Error '.$langs["ErrorPHPVersionTooLow"]." ".PHP_VERSION."
\n"; + $checkfail=1; + } + write_log('PHP Version : '.PHP_VERSION); + + // Check if Curl supported + if (! function_exists("curl_init")){ + print 'Error '.$langs["ErrorPHPDoesNotSupportCurl"]."
\n"; + $checkfail=1; + write_log('Curl is not supported'); + }else{ + print 'Ok '.$langs["PHPSupportCurl"]."
\n"; + write_log('Curl is supported'); + } + + // Check if Zip supported + if (! class_exists("ZipArchive")){ + print 'Error '.$langs["ErrorPHPDoesNotSupportZip"]."
\n"; + $checkfail=1; + write_log('Zip is not supported'); + }else{ + print 'Ok '.$langs["PHPSupportZip"]."
\n"; + write_log('Zip is supported'); + } + + // Check memory + $memrequired=64*1024*1024; + $memmaxorig=@ini_get("memory_limit"); + $memmax=@ini_get("memory_limit"); + if ($memmaxorig != ''){ + preg_match('/([0-9]+)([a-zA-Z]*)/i', $memmax, $reg); + if ($reg[2]){ + if (strtoupper($reg[2]) == 'G') $memmax=$reg[1]*1024*1024*1024; + if (strtoupper($reg[2]) == 'M') $memmax=$reg[1]*1024*1024; + if (strtoupper($reg[2]) == 'K') $memmax=$reg[1]*1024; + } + if ($memmax >= $memrequired || $memmax == -1){ + print 'Ok '.$langs["PHPMemoryOK"]." ".$memmaxorig."
\n"; + }else{ + print 'Warning '.$langs["PHPMemoryTooLow"]." ".$memmaxorig."
\n"; + } + write_log('PHP Memory limit : '.$memmaxorig); + } + + // Check if main dir is writable + if (! is_writable($dolibarr_main_document_root)){ + print 'Error '.$langs["ErrorDocRootNotWrit"]."
\n"; + $checkfail=1; + write_log('Directory is not writtable'); + }else{ + print 'Ok '.$langs["DocRootWrit"]."
\n"; + write_log('Directory is writtable'); + } + + print "
\n"; + //Display if it is new install or upgrade + if (defined('DOL_VERSION')) { + print $langs["UpgradeDetected"].': '.DOL_VERSION.''."
\n"; + }else{ + print $langs["IntallNewDetected"]."
\n"; + } + + echo '

'."\n"; + echo ''."\n"; + echo '
'."\n"; + $sourceforge_versions = get_sourceforge_files($sourceforge_rss_url); + write_log('SourceForge versions found ',$sourceforge_versions); + echo $langs["ChooseVersion"].':


'."\n"; + pFooter( $checkfail, $langs, $selectlang); +} + +//Download page +if ($action == 'download'){ + + write_log('--- Enter in Download Page ---'); + // initialize download version + if (!empty($_POST['selectversion'])){ + if ($_POST['selectversion'] == 'dev'){ + $url_version = $github_url ; + }elseif ($_POST['selectversion'] == 'stable'){ + $url_version = $github_stable ; + }elseif ($_POST['selectversion'] == 'old_stable'){ + $url_version = $github_old_stable ; + }else{ + $url_version = sprintf($sourceforge_url,$_POST['selectversion'],$_POST['selectversion']); + } + }else{ + $url_version = ''; + } + write_log('URL to download version : '.$url_version); + + $error = 0; + + pHeader($langs["Download"], 'install', $langs); + + print ''."\n"; + + print '

Database '.$langs["DownloadPackage"]." ".$_POST['selectversion']." :

\n"; + + //Check if we have an URL + if ($url_version != ''){ + print 'Ok '.$langs["UrlDownload"]." : ".$url_version."
\n"; + }else{ + print '
'.$langs["ErrorNoVersionSelectec"].'
'."
\n"; + $error=1; + } + + echo $langs["DownloadProgress"] . ' : '."
\n"; + + //Delete the file if exist + if (file_exists ($download_file)){ + if (@unlink ($download_file)){ + write_log('Archive already exist. Delete successful'); + }else{ + write_log('Archive already exist. Delete impossible'); + } + } + + //Open the archive + $file = fopen($download_file, 'wb'); // (w)rite mode (b)inary + + $new = 1; + while ($new){ + $ch = curl_init(); + curl_setopt($ch, CURLOPT_URL, $url_version); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'progress'); + curl_setopt($ch, CURLOPT_NOPROGRESS, false); // needed to make progress function work + curl_setopt($ch, CURLOPT_HEADER, 0); + curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']); + $contents = curl_exec_follow($ch); + //For Sourceforge need to extract the mirror + if (preg_match('/'.$langs["ErrorDuringDownload"]." : ".curl_error($ch)."
\n"; + $error=1; + $info = curl_getinfo($ch); + write_log('Curl Error : '.$curl_error($ch),$info); + curl_close ($ch); + exit(); + } else { + //Download is completed + fwrite($file, $contents); + fclose($file); + curl_close ($ch); + write_log('Download successful'); + } + + //Check if it is a ZIP + $zip = new ZipArchive; + $res = $zip->open($download_file); + if ($res === TRUE) { + $zip->close(); + print 'Ok '.$langs["DownloadCompleted"]." : ".human_filesize(filesize($download_file))."
\n"; + write_log('Downloaded archive is a zip. Size : '.human_filesize(filesize($download_file))); + } else { + print '
'.$langs["ErrorDownloadFile"]." : ".$res."
\n"; + $error=1; + write_log('Downloaded archive is not a zip. Error : '.$res); + } + + pFooter( $error, $langs, $selectlang); +} + +//Install page +if ($action == 'install'){ + + write_log('--- Enter in Install Page ---'); + // initialize download version + if (!empty($_POST['selectversion'])){ + $selected_version = $_POST['selectversion'] ; + if ($selected_version == 'dev'){ + $zip_directory = 'dolibarr-develop/htdocs/'; + }elseif ($selected_version == 'stable'){ + $zip_directory = 'dolibarr-'.STABLE.'/htdocs/'; + }elseif ($selected_version == 'old_stable'){ + $zip_directory = 'dolibarr-'.OLD_STABLE.'/htdocs/'; + }else{ + $zip_directory = 'dolibarr-'.$selected_version.'/htdocs/'; + } + } + + write_log('Zip directory : '.$zip_directory); + + $error = 0; + + pHeader($langs["Install"], 'redirect', $langs); + + print '

Database '.$langs["Install"]." ".$selected_version." :

\n"; + + //extract the zip + $zip = new my_ZipArchive(); + if ($zip->open($download_file) === TRUE){ + + print 'Ok '.$langs["FileIsAZip"]."
\n"; + write_log('File is a zip'); + + $output = $zip->extractSubdirTo("./", $zip_directory); + $zip->close(); + + print 'Ok '.$langs["NumbersOfDirectories"]." : ".$output["nb_directories"]."
\n"; + print 'Ok '.$langs["NumbersOfFiles"]." : ".$output["nb_files"]."
\n"; + if (count ($output["errors"]) == 0){ + print 'Ok '.$langs["NoErrors"]."
\n"; + write_log('Unzip successful. Number of directories : '.$output["nb_directories"].' Numbers of files :'.$output["nb_files"]); + }else{ + print 'Warning '.$langs["SomeErrors"]." : ".count($output["errors"])."
\n"; + write_log('Unzip successful with errors. Number of directories : '.$output["nb_directories"].' Numbers of files :'.$output["nb_files"],$output["errors"]); + } + }else{ + print '
'.$langs["ErrorNotAZip"].'
'."
\n"; + $error=1; + write_log('Archive is not a zip'); + } + + //Delete the archive + if (@unlink ($download_file)){ + write_log('Delete archive done'); + }else{ + write_log('Impossible to delete archive'); + } + + //Try to remove install.lock + $install_lock_found = false ; + $install_lock_deleted = false ; + if(file_exists($dolibarr_main_document_root.'/install.lock')){ + $install_lock_found = true ; + write_log('Install.lock found on document dir'); + if (@unlink($dolibarr_main_document_root.'/install.lock')){ + $install_lock_deleted = true ; + write_log('Install.lock deleted'); + } + } + if(file_exists($dolibarr_main_data_root.'/install.lock')){ + $install_lock_found = true ; + write_log('Install.lock found on htdocs dir'); + if (@unlink($dolibarr_main_data_root.'/install.lock')){ + $install_lock_deleted = true ; + write_log('Install.lock deleted'); + } + } + if(file_exists('install.lock')){ + $install_lock_found = true ; + write_log('Install.lock found on current dir'); + if (@unlink('install.lock')){ + $install_lock_deleted = true ; + write_log('Install.lock deleted'); + } + } + + if ($install_lock_found && $install_lock_deleted){ + print 'Ok '.$langs["InstallLockDeleted"]."
\n"; + } + if (!$install_lock_found){ + print 'Warning '.$langs["InstallLockNotFounded"]."
\n"; + } + if ($install_lock_found && !$install_lock_deleted){ + print 'Error '.$langs["InstallLockFoundNoDeleted"]."
\n"; + } + + if (!$error ){ + print "
\n"; + print "
\n"; + print $langs["RedirectToInstall"]."
\n"; + print "
\n"; + print $langs["AFewAdditionalOptions"]."
\n"; + print '
'."\n"; + print ' '.$langs["DeleteScript"]."
\n"; + print ' '.$langs["DeleteLog"]."
\n"; + } + + pFooter( $error, $langs, $selectlang); +} + +//Redirection page +if ($action == 'redirect'){ + + write_log('--- Enter in Redirect Page ---'); + + //try to remove ourselves + if (isset($_POST['removescript'])){ + if (@unlink (__FILE__)){ + write_log('Remove of this script done'); + }else{ + write_log('Not possible to remove this script'); + } + } + + //try to remove logs + if (isset($_POST['removelog'])){ + @unlink ($log_file); + } + + header("Location: install/index.php"); + exit; +} + +/*********************************************************************** +* * +* Includes * +* * +************************************************************************/ + +//Output the CSS +if ($action == 'css'){ + //set the content type header + header("Content-type: text/css"); + echo " +.opacitymedium { + opacity: 0.5; +} + +body { + font-size:14px; + font-family: roboto,arial,tahoma,verdana,helvetica; + /* background: #fcfcfc; */ + margin: 15px 30px 10px; +} + +table.main-inside { + padding-left: 10px; + padding-right: 10px; + padding-bottom: 10px; + margin-bottom: 10px; + margin-top: 10px; + color: #000000; + border-top: 1px solid #ccc; + border-bottom: 1px solid #ccc; + line-height: 22px; +} + +table.main { + padding-left: 6px; + padding-right: 6px; + padding-top: 12px; + padding-bottom: 12px; + background-color: #fff; +} + +div.titre { + padding: 5px 5px 5px 5px; + margin: 0 0 0 0; +} + +span.titre { + /* font-weight: bold; */ + background: #FFFFFF; + color: rgb(0,113,121); + border: 1px solid #bbb; + padding: 10px 10px 10px 10px; + margin: 0 0 10px 10px; +} + +div.soustitre { + font-size: 15px; + font-weight: bold; + color: #4965B3; + padding: 0 1.2em 0.5em 2em; + margin: 1.2em 1.2em 1.2em 1.2em; + border-bottom: 1px solid #999; + border-right: 1px solid #999; + text-align: right; +} + +.minwidth100 { min-width: 100px; } +.minwidth200 { min-width: 200px; } +.minwidth300 { min-width: 300px; } +.minwidth400 { min-width: 400px; } +.minwidth500 { min-width: 500px; } +.minwidth50imp { min-width: 50px !important; } +.minwidth100imp { min-width: 100px !important; } +.minwidth200imp { min-width: 200px !important; } +.minwidth300imp { min-width: 300px !important; } +.minwidth400imp { min-width: 400px !important; } +.minwidth500imp { min-width: 500px !important; } + +tr.trlineforchoice { + height: 4em; +} +a.button.runupgrade { + padding: 10px; +} + +/* Force values for small screen 570 */ +@media only screen and (max-width: 570px) +{ + body { + margin: 15px 4px 4px; + } + + input, input[type=text], input[type=password], select, textarea { + min-width: 20px; + min-height: 1.4em; + line-height: 1.4em; + padding: .4em .1em; + border: 1px solid #BBB; + /* max-width: inherit; why this ? */ + } + + .hideonsmartphone { display: none; } + .noenlargeonsmartphone { width : 50px !important; display: inline !important; } + .maxwidthonsmartphone { max-width: 100px; } + .maxwidth50onsmartphone { max-width: 40px; } + .maxwidth75onsmartphone { max-width: 50px; } + .maxwidth100onsmartphone { max-width: 70px; } + .maxwidth150onsmartphone { max-width: 120px; } + .maxwidth200onsmartphone { max-width: 200px; } + .maxwidth300onsmartphone { max-width: 300px; } + .maxwidth400onsmartphone { max-width: 400px; } + .minwidth50imp { min-width: 50px !important; } + .minwidth100imp { min-width: 50px !important; } + .minwidth200imp { min-width: 50px !important; } + .minwidth300imp { min-width: 50px !important; } + .minwidth400imp { min-width: 50px !important; } + .minwidth500imp { min-width: 50px !important; } + + table.main { + padding-left: 0; + padding-right: 0; + } + + table.main-inside { + padding-left: 1px; + padding-right: 1px; + line-height: 20px; + } + + span.titre { + font-size: 90%; + font-weight: normal; + background: #FFFFFF; + color: #444; + border: 1px solid #999; + padding: 5px 5px 5px 5px; + margin: 0 0 0 4px; + } +} + + +input:disabled +{ + background: #FDFDFD; + border: 1px solid #ACBCBB; + padding: 0 0 0 0; + margin: 0 0 0 0; + color: #AAA !important; + cursor: not-allowed !important; +} + +input[type=submit] { + border-color: #c5c5c5; + border-color: rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.15) rgba(0, 0, 0, 0.25); + display: inline-block; + padding: 4px 14px; + margin-bottom: 0; + text-align: center; + cursor: pointer; + color: #333333; + text-shadow: 0 1px 1px rgba(255, 255, 255, 0.75); + background-color: #f5f5f5; + background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6)); + background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6); + background-image: -o-linear-gradient(top, #ffffff, #e6e6e6); + background-image: linear-gradient(to bottom, #ffffff, #e6e6e6); + background-repeat: repeat-x; + filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0); + border-color: #e6e6e6 #e6e6e6 #bfbfbf; + border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25); + filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); + border: 1px solid #bbbbbb; + border-bottom-color: #a2a2a2; + -webkit-border-radius: 4px; + -moz-border-radius: 4px; + border-radius: 4px; + -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + -moz-box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); + box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.2), 0 1px 2px rgba(0, 0, 0, 0.05); +} +input:focus, textarea:focus, button:focus, select:focus { + box-shadow: 0 0 4px #8091BF; +} +input[type=text], input[type=password] { + border: 1px solid #ACBCBB; + padding: 4px; +} +select { + padding: 4px; + background-color: #fff; +} +input[type=text]:focus, input[type=password]:focus, textarea:focus, select:focus { + border: 1px solid #ACBCBB; + box-shadow: 0 0 5px #C091AF; +} +input:-webkit-autofill { + background: #FBFFEA none !important; + -webkit-box-shadow: 0 0 0 50px #FBFFEA inset; +} + +table.listofchoices, table.listofchoices tr, table.listofchoices td { + border-collapse: collapse; + padding: 8px; + color: #000000; + border: 1px solid #ccc !important; + line-height: 18px; +} + +.listofchoicesdesc { + color: #999 !important; +} +.blinkwait { + font-weight: bold; + text-decoration:blink !important; +} + +.installchoices table tr td { + margin-left: 2px; + margin-right: 2px; + border-bottom: 1px solid #999; + border-right: 1px solid #999; + color: #000000; +} + +/* OK */ +div.ok { + color: #114466; +} +span.ok { + color: #114466; +} + +/* Warning */ +div.warning { + color: #777711; +} +span.warning { + color: #777711; +} + +/* Error */ +div.error { + color: #550000; + font-weight: bold; + padding: 0.2em 0.2em 0.2em 0; + margin: 0.5em 0 0.5em 0; +} +span.error { + color: #550000; + font-weight: bold; +} + +/* Next button */ +div.nextbutton { + text-align: center; + margin-top: 10px; + padding-top: 5px; + padding-bottom: 5px; + padding-right: 10px; +} + + +div.header { + background-color: #dcdff4; + border-bottom: solid black 1px; + padding-left: 5px; + text-align: center; +} + +a:link,a:visited,a:active { + text-decoration:none; + color: #114466; +} +a:hover { + text-decoration:underline; +} + +a.titre { + text-decoration:none; +} + + +div.comment { + text-decoration:none; + color:black; +} + +h3 { + margin-top: 20px; + font-size:16px; + font-weight: normal; + color: rgb(100,60,20); + /* text-shadow: 1px 1px 1px #c0c0c0; */ +} + +tr.bg1 { + background-color: #E5E5E5; +} + +tr.bg2 { + background-color: #B5C5C5; +} + +/* Class for parameters key and value */ +td.label { + color: #5945A3; + padding: 5px 5px 5px 5px; + margin: 0 0 0 0; + border-bottom: 1px solid #CCCCDB; +} + +/* Class for parameters example */ +td.comment { + color: black; + padding: 5px 5px 5px 5px; + margin: 0 0 0 0; + text-decoration:none; + font-size: 12px; + border-bottom: 1px solid #CCCCDB; +} + +.install +{ + border: 1px solid #999; + padding: 4px 4px 4px 4px; +} + +div.visible { + display: block; +} + +div.hidden { + display: none; +} + +ul { + margin: 0; + padding-top: 0; + padding-bottom: 0; +} + +tr.choiceselected td.listofchoicesdesc { + color: #000 !important; +} + +tr.choiceselected td .button { + background: rgb(0,113,121); + color: #fff; +} + +a.button:link,a.button:visited,a.button:active { + color: #888; +} +.button { + background: #ddd; + color: #fff; + /* border: 1px solid #e0e0e0; */ + padding: 0.5em 0.7em; + margin: 0 0.5em; + -moz-border-radius: 3px; + -webkit-border-radius: 3px; + border-radius: 3px; + -moz-box-shadow: 2px 2px 3px #ddd; + -webkit-box-shadow: 2px 2px 3px #ddd; + box-shadow: 2px 2px 3px #ddd; +} +a.button:hover { + text-decoration:none; +} + +.suggestedchoice { + color: rgba(70, 3, 62, 0.6) !important; + /* background-color: rgba(70, 3, 62, 0.3); */ + padding: 2px 4px; + border-radius: 4px; + white-space: nowrap; +} +.choiceselected { + background-color: #f4f6f4; + background-repeat: repeat-x; + background-position: top left; +} + +.center { + text-align: center; +} + +.valignmiddle { + vertical-align: middle; +} + +.valigntextbottom { + vertical-align: text-bottom; +}"; + exit(); +} + +//Output the images +if ($action == 'img'){ + // initialize file variable + $file = (!empty($_GET['file'])) ? $_GET['file'] : ''; + + if ($file == 'logo'){ + header("Content-type: image/svg+xml"); + echo base64_decode("PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIKICAgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgd2lkdGg9IjcyMCIKICAgaGVpZ2h0PSIyMDAiCiAgIGlkPSJzdmczNDUwIgogICB2ZXJzaW9uPSIxLjEiCiAgIGlua3NjYXBlOnZlcnNpb249IjAuOTIuMyAoMjQwNTU0NiwgMjAxOC0wMy0xMSkiCiAgIHNvZGlwb2RpOmRvY25hbWU9ImRvbGliYXJyX2xvZ28uc3ZnIgogICBpbmtzY2FwZTpleHBvcnQtZmlsZW5hbWU9Ii9ob21lL2xkZXN0YWlsbGV1ci9naXQvZG9saWJhcnItZm91bmRhdGlvbi9sb2dvLWNsaXBhcnRzL2RvbGliYXJyX2xvZ28ucG5nIgogICBpbmtzY2FwZTpleHBvcnQteGRwaT0iNzcuMzYyODMxIgogICBpbmtzY2FwZTpleHBvcnQteWRwaT0iNzcuMzYyODMxIj4KICA8dGl0bGUKICAgICBpZD0idGl0bGUzMDcyIj5Mb2dvIERvbGliYXJyIEVSUC1DUk08L3RpdGxlPgogIDxkZWZzCiAgICAgaWQ9ImRlZnMzNDUyIj4KICAgIDxsaW5lYXJHcmFkaWVudAogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50MzczNC0zLTYiPgogICAgICA8c3RvcAogICAgICAgICBzdHlsZT0ic3RvcC1jb2xvcjojNDk0OTZmO3N0b3Atb3BhY2l0eToxIgogICAgICAgICBvZmZzZXQ9IjAiCiAgICAgICAgIGlkPSJzdG9wMzczNiIgLz4KICAgICAgPHN0b3AKICAgICAgICAgc3R5bGU9InN0b3AtY29sb3I6IzQ1NDU1YTtzdG9wLW9wYWNpdHk6MSIKICAgICAgICAgb2Zmc2V0PSIxIgogICAgICAgICBpZD0ic3RvcDM3MzgiIC8+CiAgICA8L2xpbmVhckdyYWRpZW50PgogICAgPGxpbmVhckdyYWRpZW50CiAgICAgICBpbmtzY2FwZTpjb2xsZWN0PSJhbHdheXMiCiAgICAgICB4bGluazpocmVmPSIjbGluZWFyR3JhZGllbnQzNzM0LTMtNiIKICAgICAgIGlkPSJsaW5lYXJHcmFkaWVudDQ2MzYiCiAgICAgICBncmFkaWVudFVuaXRzPSJ1c2VyU3BhY2VPblVzZSIKICAgICAgIHgxPSI3NS42OTc0NDEiCiAgICAgICB5MT0iMzEwLjUzMzkxIgogICAgICAgeDI9Ijc0Mi45ODAwNCIKICAgICAgIHkyPSIzMTAuNTMzOTEiIC8+CiAgICA8bGluZWFyR3JhZGllbnQKICAgICAgIGlua3NjYXBlOmNvbGxlY3Q9ImFsd2F5cyIKICAgICAgIHhsaW5rOmhyZWY9IiNsaW5lYXJHcmFkaWVudDM3MzQtMy02IgogICAgICAgaWQ9ImxpbmVhckdyYWRpZW50ODk5IgogICAgICAgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiCiAgICAgICB4MT0iNzUuNjk3NDQxIgogICAgICAgeTE9IjMxMC41MzM5MSIKICAgICAgIHgyPSI3NDIuOTgwMDQiCiAgICAgICB5Mj0iMzEwLjUzMzkxIiAvPgogIDwvZGVmcz4KICA8c29kaXBvZGk6bmFtZWR2aWV3CiAgICAgaWQ9ImJhc2UiCiAgICAgcGFnZWNvbG9yPSIjZmZmZmZmIgogICAgIGJvcmRlcmNvbG9yPSIjNjY2NjY2IgogICAgIGJvcmRlcm9wYWNpdHk9IjEuMCIKICAgICBpbmtzY2FwZTpwYWdlb3BhY2l0eT0iMCIKICAgICBpbmtzY2FwZTpwYWdlc2hhZG93PSIyIgogICAgIGlua3NjYXBlOnpvb209IjEuNDE0MjEzNiIKICAgICBpbmtzY2FwZTpjeD0iMzkxLjY3ODIiCiAgICAgaW5rc2NhcGU6Y3k9Ii01MC4zNjYwMTUiCiAgICAgaW5rc2NhcGU6Y3VycmVudC1sYXllcj0iZzQ2NDgiCiAgICAgaW5rc2NhcGU6ZG9jdW1lbnQtdW5pdHM9InB4IgogICAgIHNob3dncmlkPSJmYWxzZSIKICAgICBpbmtzY2FwZTp3aW5kb3ctd2lkdGg9IjE5MjAiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTAyMyIKICAgICBpbmtzY2FwZTp3aW5kb3cteD0iMCIKICAgICBpbmtzY2FwZTp3aW5kb3cteT0iMCIKICAgICBpbmtzY2FwZTp3aW5kb3ctbWF4aW1pemVkPSIxIgogICAgIGlua3NjYXBlOnNob3dwYWdlc2hhZG93PSJmYWxzZSIKICAgICBzaG93Ym9yZGVyPSJ0cnVlIgogICAgIGJvcmRlcmxheWVyPSJmYWxzZSIKICAgICBmaXQtbWFyZ2luLXRvcD0iMjQiCiAgICAgZml0LW1hcmdpbi1sZWZ0PSIyNCIKICAgICBmaXQtbWFyZ2luLXJpZ2h0PSIwIgogICAgIGZpdC1tYXJnaW4tYm90dG9tPSIwIgogICAgIHNob3dndWlkZXM9InRydWUiCiAgICAgaW5rc2NhcGU6Z3VpZGUtYmJveD0idHJ1ZSIKICAgICBpbmtzY2FwZTptZWFzdXJlLXN0YXJ0PSIwLDAiCiAgICAgaW5rc2NhcGU6bWVhc3VyZS1lbmQ9IjAsMCIKICAgICBpbmtzY2FwZTpwYWdlY2hlY2tlcmJvYXJkPSJ0cnVlIj4KICAgIDxpbmtzY2FwZTpncmlkCiAgICAgICB0eXBlPSJ4eWdyaWQiCiAgICAgICBpZD0iZ3JpZDE0NTgiIC8+CiAgPC9zb2RpcG9kaTpuYW1lZHZpZXc+CiAgPG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhMzQ1NSI+CiAgICA8cmRmOlJERj4KICAgICAgPGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPgogICAgICAgIDxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PgogICAgICAgIDxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz4KICAgICAgICA8ZGM6dGl0bGU+TG9nbyBEb2xpYmFyciBFUlAtQ1JNPC9kYzp0aXRsZT4KICAgICAgICA8Y2M6bGljZW5zZQogICAgICAgICAgIHJkZjpyZXNvdXJjZT0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbGljZW5zZXMvYnktbmQvNC4wLyIgLz4KICAgICAgICA8ZGM6Y3JlYXRvcj4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkxhdXJlbnQgRGVzdGFpbGxldXI8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOmNyZWF0b3I+CiAgICAgICAgPGRjOnJpZ2h0cz4KICAgICAgICAgIDxjYzpBZ2VudD4KICAgICAgICAgICAgPGRjOnRpdGxlPkxhdXJlbnQgRGVzdGFpbGxldXI8L2RjOnRpdGxlPgogICAgICAgICAgPC9jYzpBZ2VudD4KICAgICAgICA8L2RjOnJpZ2h0cz4KICAgICAgPC9jYzpXb3JrPgogICAgICA8Y2M6TGljZW5zZQogICAgICAgICByZGY6YWJvdXQ9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL2xpY2Vuc2VzL2J5LW5kLzQuMC8iPgogICAgICAgIDxjYzpwZXJtaXRzCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyNSZXByb2R1Y3Rpb24iIC8+CiAgICAgICAgPGNjOnBlcm1pdHMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zI0Rpc3RyaWJ1dGlvbiIgLz4KICAgICAgICA8Y2M6cmVxdWlyZXMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zI05vdGljZSIgLz4KICAgICAgICA8Y2M6cmVxdWlyZXMKICAgICAgICAgICByZGY6cmVzb3VyY2U9Imh0dHA6Ly9jcmVhdGl2ZWNvbW1vbnMub3JnL25zI0F0dHJpYnV0aW9uIiAvPgogICAgICA8L2NjOkxpY2Vuc2U+CiAgICA8L3JkZjpSREY+CiAgPC9tZXRhZGF0YT4KICA8ZwogICAgIGlkPSJsYXllcjEiCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6Z3JvdXBtb2RlPSJsYXllciIKICAgICBzdHlsZT0iZGlzcGxheTppbmxpbmUiCiAgICAgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTUxLjQxMzY4MSwtMTk5LjYwOTU3KSI+CiAgICA8ZwogICAgICAgaWQ9Imc0NTkyIj4KICAgICAgPGcKICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDQ2MzYpO2ZpbGwtb3BhY2l0eToxIgogICAgICAgICBpZD0iZzQ2MjYiPgogICAgICAgIDxnCiAgICAgICAgICAgc3R5bGU9ImZpbGw6dXJsKCNsaW5lYXJHcmFkaWVudDg5OSkiCiAgICAgICAgICAgaWQ9Imc0NjQ4Ij4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjY2Njc2Nzc3NjY3Nzc2MiCiAgICAgICAgICAgICBkPSJtIDExMi4zMjkxMywyODAuMjk0NzYgdiA5OC4wMjU4OSBsIC0zNi42MzE2ODgsLTAuNDAxMjMgdiAwLjQwMTIzIC0xMzcuMzU2NzIgaCA0Ny43Mjk0NjggYyAyMC45MzIzOSwwIDM3LjMyMzQxLDUuMjg0MjQgNDkuMTczMDcsMTUuODUyNzIgMTQuMDc1MjMsMTIuNjQyMDQgMjEuMTEyODUsMjkuNzk5MSAyMS4xMTI4NSw1MS40NzExNyAwLDIwLjczNTYzIC02LjAxNTA2LDM3LjY1ODU3IC0xOC4wNDUxNyw1MC43Njg4NCAtMTIuMDMwMTEsMTMuMTEwMjcgLTI3LjIwNjM3LDE5LjM1MjkxIC00Ni4xNTM4LDE5LjM1MjkxIC0yLjIyNTU3LDAgLTYuMjM5NjgsLTAuMDcxMyAtMTEuMjI5ODIsLTAuMDg4OCB2IC00MC4yMzM3OSBsIDEwLjA4OTU0LC0wLjA1NDIgYyAyMS4zNTMxNCwtMC4xMTQ2OSAyNy44MDUzLC05Ljg3ODg1IDI3LjgwNTMsLTI5Ljc0NDkyIDAsLTE4LjY2MjA2IC0xMC40OTYyNywtMjcuOTkzMDkgLTMxLjQ4ODgxLC0yNy45OTMwOSB6IgogICAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToxOTQuODU4MjMwNTlweDtsaW5lLWhlaWdodDoxMjUlO2ZvbnQtZmFtaWx5OidCYXVoYXVzIDkzJzstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidCYXVoYXVzIDkzJzt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMyNjNjNWM7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjEuNzA3Mjk0NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eTowLjE4NDMxMzczIgogICAgICAgICAgICAgaWQ9InBhdGg4NDYzIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBkPSJtIDI1MS4xODY2OSwyNzQuMjYzMjIgcSAxOS4xMjc4NywwIDMyLjc1MTk3LDE1LjM1MTA2IDEzLjcxNDMyLDE1LjI1MDcxIDEzLjcxNDMyLDM2LjYyMTc5IDAsMjEuNjcyMDYgLTEzLjg5NDc4LDM2LjkyMjc5IC0xMy44MDQ1NSwxNS4yNTA3MSAtMzMuMzgzNTYsMTUuMjUwNzEgLTE5LjU3ODk5LDAgLTMzLjQ3Mzc3LC0xNS4yNTA3MSAtMTMuODk0NzksLTE1LjM1MTA1IC0xMy44OTQ3OSwtMzYuOTIyNzkgMCwtMjEuOTczMDggMTMuODk0NzksLTM2LjkyMjggMTMuODk0NzgsLTE1LjA1MDA1IDM0LjI4NTgyLC0xNS4wNTAwNSB6IG0gLTAuOTAyMjcsMzcuMDIzMTMgcSAtNS40MTM1NSwwIC05LjIwMzAzLDQuNDE0NjggLTMuNzg5NDksNC4zMTQzNSAtMy43ODk0OSwxMC42MzUzNyAwLDYuMjIwNjggMy43ODk0OSwxMC42MzUzNyAzLjg3OTcxLDQuNDE0NjggOS4yMDMwMyw0LjQxNDY4IDUuNDEzNTYsMCA5LjIwMzA0LC00LjQxNDY4IDMuODc5NywtNC40MTQ2OSAzLjg3OTcsLTEwLjYzNTM3IDAsLTYuMzIxMDIgLTMuNzg5NDcsLTEwLjYzNTM3IC0zLjc4OTQ5LC00LjQxNDY4IC05LjI5MzI3LC00LjQxNDY4IHoiCiAgICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjE5NC44NTgyMzA1OXB4O2xpbmUtaGVpZ2h0OjEyNSU7Zm9udC1mYW1pbHk6J0JhdWhhdXMgOTMnOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J0JhdWhhdXMgOTMnO3RleHQtYWxpZ246c3RhcnQ7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzI2M2M1YztmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS43MDcyOTQ3O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjAuMTg0MzEzNzMiCiAgICAgICAgICAgICBpZD0icGF0aDg0NjUiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICAgICAgPHBhdGgKICAgICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2NjY2MiCiAgICAgICAgICAgICBkPSJNIDM0NS40NzI2OCwyNDEuMDUyODcgViAzNzguNDA5NTYgSCAzMTEuNzI4MjIgViAyNDEuMDUyODcgWiIKICAgICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6MTk0Ljg1ODIzMDU5cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTonQmF1aGF1cyA5Myc7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonQmF1aGF1cyA5Myc7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMjYzYzVjO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjcwNzI5NDc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MC4xODQzMTM3MyIKICAgICAgICAgICAgIGlkPSJwYXRoODQ2NyIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgICAgICA8cGF0aAogICAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjc3Njc2NzY2NzY3Nzc2Njc2NjIgogICAgICAgICAgICAgZD0ibSA0NTAuNjc2LDIzOS45ODQ1OCB2IDgxLjk3MjYxIGMgMCwxMy4zMTA5MyA0LjMwMDc2LDE5Ljk2NjQgMTIuOTAyMjksMTkuOTY2NCAzLjY2OTE4LDAgNi43NjY5MywtMS4zNzEyMyA5LjI5MzI2LC00LjExMzY4IDIuNTg2NDcsLTIuODA5MzUgMy44Nzk3MSwtNi4xODcyNSAzLjg3OTcxLC0xMC4xMzM3IDAsLTQuMDgwMjMgLTEuMjAzMDEsLTcuNDkxNTggLTMuNjA5MDMsLTEwLjIzNDAzIC0yLjQwNjAzLC0yLjgwOTM1IC01LjM1MzQsLTQuMjE0MDIgLTguODQyMTMsLTQuMjE0MDIgLTIuNDY2MTcsMCAtOC4yMzEyMywtMC4wMTMgLTguMjMxMjMsLTAuMDEzIGwgLTAuMjUsLTM4LjA4NzQ3IGMgMCwwIDYuOTc3NDcsLTAuMjI3MDEgOS4wMjI1OCwtMC4yMjcwMSAxMi42OTE3NywwIDIzLjU0ODk1LDUuMDgzNTggMzIuNTcxNTMsMTUuMjUwNzMgOS4wODI3MywxMC4xNjcxNCAxMy42MjQxLDIyLjQwNzg1IDEzLjYyNDEsMzYuNzIyMTIgMCwxNC42NDg3MiAtNS4xNDU2MiwyNi41MTY2IC0xMy44MDQ1NSwzNy4wMjMxMyAtOC41NzgwMywxMC40MDgzNiAtMjIuOTg2MjEsMTQuNTk5OTMgLTMzLjkyNDkxLDE0LjUxMTU0IC02LjczNjY0LC0wLjA1NDQgLTEzLjMyMzM1LC0xLjEwMDI0IC0xOS43NTk0NywtNC4zNzc4NCAtNi4zNzU5NSwtMy4yNzc1NyAtMTEuNjM5MTIsLTcuNjkyMjUgLTE1Ljc4OTUxLC0xMy4yNDQwNCAtNy4yMTgwNywtOS42MzIwMyAtMTAuODI3MSwtMjIuMTA2ODYgLTEwLjgyNzEsLTM3LjQyNDQ3IHYgLTgzLjM3NzI4IHoiCiAgICAgICAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjE5NC44NTgyMzA1OXB4O2xpbmUtaGVpZ2h0OjEyNSU7Zm9udC1mYW1pbHk6J0JhdWhhdXMgOTMnOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246J0JhdWhhdXMgOTMnO3RleHQtYWxpZ246c3RhcnQ7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzI2M2M1YztmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS43MDcyOTQ3O3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjAuMTg0MzEzNzMiCiAgICAgICAgICAgICBpZD0icGF0aDg0NzEiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIiAvPgogICAgICAgICAgPHBhdGgKICAgICAgICAgICAgIHNvZGlwb2RpOm5vZGV0eXBlcz0iY2Nzc3Njc2NzY2NzY3Njc2NzY2MiCiAgICAgICAgICAgICBkPSJtIDU3NS42NjY0OSwzNDIuOTgzNTQgLTAuMTU2MjUsMzUuNDI2MDIgYyAwLDAgLTUuMDc0NSwwIC03LjM2MDIyLDAgLTEzLjUzMzg3LDAgLTI0LjgxMjEsLTMuMjQ0MDMgLTMzLjgzNDY4LC0xMy4xNDM2MiAtOS4wMjI1OSwtOS44OTk1OSAtMTMuNTMzODgsLTIyLjMwNzUzIC0xMy41MzM4OCwtMzcuMjIzOCAwLC0xNC41MTQ5NCA0LjU0MTM3LC0yNi44MjI1NCAxMy42MjQxLC0zNi45MjI3OSA5LjE0Mjg5LC0xMC4xMDAyNiAyMC4yNDA2NiwtMTUuMTUwMzkgMzMuMjkzMzMsLTE1LjE1MDM5IDE0LjU1NjQzLDAgMjYuMDE1MTEsNC43NDkxMyAzNC4zNzYwNCwxNC4yNDczOSA4LjQyMTA4LDkuNDMxMzYgMTIuNjMxNjIsMjIuMzQwOTYgMTIuNjMxNjIsMzguNzI4NzkgbCAtMC4wNjI1LDQ5LjQ2NDQyIGggLTMzLjgwNjk2IGwgMC4xMjUsLTQ2Ljc1NTQxIGMgMC4wMTQxLC01LjI4NDIxIC0xLjE3MjkzLC05LjQ5ODI0IC0zLjUxODgsLTEyLjY0MjAzIC0yLjI4NTczLC0zLjE0Mzc5IC01LjM4MzQ4LC00LjcxNTY5IC05LjI5MzI3LC00LjcxNTY5IC0zLjU0ODg5LDAgLTYuNjE2NTcsMS40MzgxMSAtOS4yMDMwNCw0LjMxNDM0IC0yLjU4NjQ3LDIuODc2MjMgLTMuODc5NzEsNi4yODc1OCAtMy44Nzk3MSwxMC4yMzQwNSAwLDQuMTQ3MTIgMS4xNzI5NCw3LjU1ODQ2IDMuNTE4ODEsMTAuMjM0MDMgMi4zNDU4NywyLjY3NTU2IDUuMzIzMzMsNC4wMTMzNCA4LjkzMjM2LDQuMDEzMzQgMi45NDczNywwIDguMTQ4MDUsLTAuMTA4NjcgOC4xNDgwNSwtMC4xMDg2NyB6IgogICAgICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6Ym9sZDtmb250LXN0cmV0Y2g6bm9ybWFsO2ZvbnQtc2l6ZToxOTQuODU4MjMwNTlweDtsaW5lLWhlaWdodDoxMjUlO2ZvbnQtZmFtaWx5OidCYXVoYXVzIDkzJzstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidCYXVoYXVzIDkzJzt0ZXh0LWFsaWduOnN0YXJ0O3dyaXRpbmctbW9kZTpsci10Yjt0ZXh0LWFuY2hvcjpzdGFydDtmaWxsOiMyNjNjNWM7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjEuNzA3Mjk0NztzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbWl0ZXJsaW1pdDo0O3N0cm9rZS1kYXNoYXJyYXk6bm9uZTtzdHJva2Utb3BhY2l0eTowLjE4NDMxMzczIgogICAgICAgICAgICAgaWQ9InBhdGg4NDczIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIgLz4KICAgICAgICAgIDxwYXRoCiAgICAgICAgICAgICBzb2RpcG9kaTpub2RldHlwZXM9ImNjc3NjY3Njc2MiCiAgICAgICAgICAgICBkPSJtIDY4My42NjMwNSwyNzUuODc2NjcgMC4wMDQsMzguOTE2NjIgYyAwLDAgLTQuNDE4NzIsMC4xMDUxNyAtNi4zNDM1MywwLjEwNTE3IC02LjEzNTM1LDAgLTkuMjAzMDMsNS4yMTczNSAtOS4yMDMwMywxNS42NTIwNCB2IDQ3Ljg1OTA2IGggLTMzLjc0NDQ3IHYgLTU1LjA4MzA4IGMgMCwtMTQuNDQ4MDUgMy41NDg4OCwtMjUuOTUyOTggMTAuNjQ2NjUsLTM0LjUxNDc5IDcuMDk3NzcsLTguNjI4NjkgMTYuNTcxNDgsLTEyLjk0MzA0IDI4LjQyMTE0LC0xMi45NDMwNCAyLjY0NjYyLDAgMTAuMjE5NDUsMC4wMDggMTAuMjE5NDUsMC4wMDggeiIKICAgICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6MTk0Ljg1ODIzMDU5cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTonQmF1aGF1cyA5Myc7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonQmF1aGF1cyA5Myc7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMjYzYzVjO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjcwNzI5NDc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MC4xODQzMTM3MyIKICAgICAgICAgICAgIGlkPSJwYXRoODQ3NSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgICAgICA8cGF0aAogICAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY3NzY2NzY3NjYyIKICAgICAgICAgICAgIGQ9Im0gNzQyLjk3OTk5LDI3NS44Nzg1NyAtMC4wMzEyLDM4Ljk0NTk3IGMgMCwwIC00LjUxMjQ3LDAuMDczOSAtNi40MzcyOCwwLjA3MzkgLTYuMTM1MzcsMCAtOS4yMDMwNSw1LjIxNzM1IC05LjIwMzA1LDE1LjY1MjA0IHYgNDcuODU5MDYgaCAtMzMuNzQ0NDUgdiAtNTUuMDgzMDggYyAwLC0xNC40NDgwNSAzLjU0ODg4LC0yNS45NTI5OCAxMC42NDY2NCwtMzQuNTE0NzkgNy4wOTc3NywtOC42Mjg2OSAxNi41NzE0OSwtMTIuOTQzMDQgMjguNDIxMTQsLTEyLjk0MzA0IDIuNjQ2NjMsMCAxMC4zNDgyNSwwLjAxIDEwLjM0ODI1LDAuMDEgeiIKICAgICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6MTk0Ljg1ODIzMDU5cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTonQmF1aGF1cyA5Myc7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonQmF1aGF1cyA5Myc7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMjYzYzVjO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjcwNzI5NDc7c3Ryb2tlLWxpbmVjYXA6cm91bmQ7c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLW9wYWNpdHk6MC4xODQzMTM3MyIKICAgICAgICAgICAgIGlkPSJwYXRoODQ3NyIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgICAgICA8cGF0aAogICAgICAgICAgICAgc29kaXBvZGk6bm9kZXR5cGVzPSJjY2NjYyIKICAgICAgICAgICAgIGQ9Im0gMzk4LjkxMzc4LDI3Ni40MDk1NyB2IDEwMiBoIC0zMy43NDQ0NiB2IC0xMDIgeiIKICAgICAgICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0OmJvbGQ7Zm9udC1zdHJldGNoOm5vcm1hbDtmb250LXNpemU6MTk0Ljg1ODIzMDU5cHg7bGluZS1oZWlnaHQ6MTI1JTtmb250LWZhbWlseTonQmF1aGF1cyA5Myc7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonQmF1aGF1cyA5Myc7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7ZGlzcGxheTppbmxpbmU7ZmlsbDojMjYzYzVjO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lO3N0cm9rZS13aWR0aDoxLjQ3MTI0MDUyO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1taXRlcmxpbWl0OjQ7c3Ryb2tlLWRhc2hhcnJheTpub25lO3N0cm9rZS1vcGFjaXR5OjAuMTg0MzEzNzMiCiAgICAgICAgICAgICBpZD0icGF0aDg0NjctNSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiIC8+CiAgICAgICAgPC9nPgogICAgICA8L2c+CiAgICA8L2c+CiAgICA8dGV4dAogICAgICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSIKICAgICAgIHN0eWxlPSJmb250LXN0eWxlOm5vcm1hbDtmb250LXZhcmlhbnQ6bm9ybWFsO2ZvbnQtd2VpZ2h0Om5vcm1hbDtmb250LXN0cmV0Y2g6bm9ybWFsO2xpbmUtaGVpZ2h0OjAlO2ZvbnQtZmFtaWx5OkFyaWFsOy1pbmtzY2FwZS1mb250LXNwZWNpZmljYXRpb246QXJpYWw7dGV4dC1hbGlnbjpzdGFydDt3cml0aW5nLW1vZGU6bHItdGI7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMDA3YjhjO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lOyIKICAgICAgIHg9IjY0My4zMTE0NiIKICAgICAgIHk9IjIyOS43NzIxMSIKICAgICAgIGlkPSJ0ZXh0NTQ4NCIKICAgICAgIHRyYW5zZm9ybT0ic2NhbGUoMC44ODUzMzIxMywxLjEyOTUxOTYpIj48dHNwYW4KICAgICAgICAgc3R5bGU9ImZvbnQtc3R5bGU6bm9ybWFsO2ZvbnQtdmFyaWFudDpub3JtYWw7Zm9udC13ZWlnaHQ6bm9ybWFsO2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjQyLjk1MjE5ODAzcHg7bGluZS1oZWlnaHQ6MTAwJTtmb250LWZhbWlseTpBcmlhbDstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOkFyaWFsO3RleHQtYWxpZ246c3RhcnQ7d3JpdGluZy1tb2RlOmxyLXRiO3RleHQtYW5jaG9yOnN0YXJ0O2ZpbGw6IzAwN2I4YztmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZTsiCiAgICAgICAgIHNvZGlwb2RpOnJvbGU9ImxpbmUiCiAgICAgICAgIGlkPSJ0c3BhbjU0ODYiCiAgICAgICAgIHg9IjY0My4zMTE0NiIKICAgICAgICAgeT0iMjI5Ljc3MjExIj5FUlAvQ1JNPC90c3Bhbj48L3RleHQ+CiAgICA8ZWxsaXBzZQogICAgICAgc3R5bGU9ImZpbGw6IzAwN2I4YztmaWxsLW9wYWNpdHk6MTtzdHJva2U6bm9uZTtzdHJva2Utd2lkdGg6MS4wMjk5OTEyNztzdHJva2Utb3BhY2l0eToxIgogICAgICAgaWQ9InBhdGg5NTciCiAgICAgICBjeD0iMzgxLjk0MTkzIgogICAgICAgY3k9IjI0Ny41ODE2MiIKICAgICAgIHJ4PSIxNy40NTY2OTkiCiAgICAgICByeT0iMTguMTE5NjEyIiAvPgogIDwvZz4KPC9zdmc+Cg=="); + exit(); + } + + if ($file == 'gear'){ + header("Content-type: image/svg+xml"); + echo base64_decode("PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNCIgaGVpZ2h0PSIxNiIgdmlld0JveD0iMCAwIDE0IDE2Ij48cGF0aCBmaWxsLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNCA4Ljc3di0xLjZsLTEuOTQtLjY0LS40NS0xLjA5Ljg4LTEuODQtMS4xMy0xLjEzLTEuODEuOTEtMS4wOS0uNDUtLjY5LTEuOTJoLTEuNmwtLjYzIDEuOTQtMS4xMS40NS0xLjg0LS44OC0xLjEzIDEuMTMuOTEgMS44MS0uNDUgMS4wOUwwIDcuMjN2MS41OWwxLjk0LjY0LjQ1IDEuMDktLjg4IDEuODQgMS4xMyAxLjEzIDEuODEtLjkxIDEuMDkuNDUuNjkgMS45MmgxLjU5bC42My0xLjk0IDEuMTEtLjQ1IDEuODQuODggMS4xMy0xLjEzLS45Mi0xLjgxLjQ3LTEuMDlMMTQgOC43NXYuMDJ6TTcgMTFjLTEuNjYgMC0zLTEuMzQtMy0zczEuMzQtMyAzLTMgMyAxLjM0IDMgMy0xLjM0IDMtMyAzeiIvPjwvc3ZnPg=="); + exit(); + } + + if ($file == 'tick'){ + header("Content-type: image/png"); + echo base64_decode("iVBORw0KGgoAAAANSUhEUgAAAA4AAAAOCAMAAAAolt3jAAAASFBMVEX////d898xuUBUxWHD68cgszETryWD1Yyc3aQYsSmY3KDY8ttPw11ky3AltTXt+e960oTy+/OP2Zil4aw1u0VcyGnH7MzL7c+AO76zAAAAAXRSTlMAQObYZgAAAElJREFUCNd9ztEKgCAMheFR+c9SFCrx/d+0G2ETwt197HA4IovrkxSvHc8M0dTwTx26CzzyjmQCKNWSGfA18QQuqzkCOu3Z/kd/sbUB0OenPPYAAAAASUVORK5CYII="); + exit(); + } + + if ($file == 'warning'){ + header("Content-type: image/png"); + echo base64_decode("iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAABmJLR0QA3wCRAAAON4EwAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH3wwEEhoU0HsntAAAARVJREFUOMvNk71KQ0EQhb9rkspGlEGD+gRp/KlSiKRR0EaxmDponUTtBDuNpTapY6OQpxjwCULAF9BGCT5DbCZwve41WQtxYNiZs7OHmbO78FdmKmVTKU+qK07B1QFGwNFPRTMTutkCdoBdj+OJTKUEnAGz7qeORXdUBQ5S+aFj0USPAewhishUboBlT+/cAVZMpR06kwRIKsATMO/Qqq+vvn4A27Xe8Dm3I1MpAM0UScgWgIbX5r6jClDPYOcBsrq/r0Ee0X0GGwGtVDyWogR0gc1vo5nKCbAe0HDOPavnhqkcfxHbVJaAPrAYGGN8Y63A3huwVusN3xNTSYAr4OKX//oauCz6LewBL65DjCXAPnDLv7NPrj00Vfm5cGcAAAAASUVORK5CYII="); + exit(); + } + + if ($file == 'error'){ + header("Content-type: image/png"); + echo base64_decode("iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAAB3RJTUUH4AwMCisRROG71gAAAQ5JREFUOMvNk71KA0EUhb85amUjKsSgPkEa41YWwcYHUHyCoLW/nWAXTZvGR9CXsLO/QQSfwEYLrVLP2tzAZp1EN4J44TLMmbPf3js/8FdhUt2k+ne+2R+wboAc2P9NNS2TBp6tSV5NgMwBZ8C856lr1UDAFrBbmO+5Vhl0l9BuK4FM6gKrPu15AqyZdJ36JiQgDeABWHRp3ccXH9+B7SzG57EVmTQDHBcgqVgCjtw79h41gHZJO0/A2n6/npKtmdQHmgUpL3jykr+fxZh9ac2kwxJk+KMFz/J+bpp0MFKRSSvAI1BLtDE8sZPE2iuwkcX4FkwKQAe4mPIlXQGXwaRl4N5PKq8ICcAHsMO/i0/KdzaZfIaieAAAAABJRU5ErkJggg=="); + exit(); + } +}