10.2 API imagetag

This commit is contained in:
Fred Tempez 2020-05-25 11:58:54 +02:00
parent 098eca657f
commit d75ec190b5
4 changed files with 122 additions and 121 deletions

View File

@ -5,9 +5,10 @@
- Gestion des accès concurrents :
- deux utilisateurs ne peuvent accèder en modification à la même page du site ou de configuration
- la connexion d'un utilisateur sur un autre poste ou navigateur déconnecte la session précédente.
- Modifications :
- Modifications :
- Thème, les sélecteurs de couleur affiche la valeur RGBa d'une couleur différente de celle de la sélection.
- Thème de l'administration, amélioration du rendu.
- Image tag : modification de l'API Google.
## version 10.1.000
- Nouveautés :

View File

@ -357,7 +357,7 @@ class common {
* En local, copie du site décran de ZwiiCMS
*/
public function makeImageTag () {
if (!file_exists(self::FILE_DIR.'source/screenshot.png'))
if (!file_exists(self::FILE_DIR.'source/screenshot.jpg'))
{
if ( strpos(helper::baseUrl(false),'localhost') == 0 AND strpos(helper::baseUrl(false),'127.0.0.1') == 0) {
$googlePagespeedData = helper::urlGetContents('https://www.googleapis.com/pagespeedonline/v2/runPagespeed?url='. helper::baseUrl(false) .'&screenshot=true');
@ -367,7 +367,7 @@ class common {
$screenshot = str_replace(array('_','-'),array('/','+'),$screenshot);
$data = 'data:image/jpeg;base64,'.$screenshot;
$data = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data));
file_put_contents( self::FILE_DIR.'source/screenshot.png',$data);
file_put_contents( self::FILE_DIR.'source/screenshot.jpg',$data);
}
}
}
@ -2424,7 +2424,7 @@ class layout extends common {
* Affiche la meta image (site screenshot)
*/
public function showMetaImage() {
echo '<meta property="og:image" content="' . helper::baseUrl() .self::FILE_DIR.'source/screenshot.png" />';
echo '<meta property="og:image" content="' . helper::baseUrl() .self::FILE_DIR.'source/screenshot.jpg" />';
}

View File

@ -26,7 +26,7 @@ class config extends common {
'updateBaseUrl' => self::GROUP_ADMIN,
'script' => self::GROUP_ADMIN
];
public static $timezones = [
'Pacific/Midway' => '(GMT-11:00) Midway Island',
'US/Samoa' => '(GMT-11:00) Samoa',
@ -147,7 +147,7 @@ class config extends common {
5 => '5 articles',
10 => '10 articles',
15 => '15 articles',
20 => '20 articles'
20 => '20 articles'
];
// Type de proxy
public static $proxyType = [
@ -187,7 +187,7 @@ class config extends common {
}
/**
* Met à jour un fichier robots.txt lors du changement de réécriture
* Met à jour un fichier robots.txt lors du changement de réécriture
*/
public function updateRobots() {
@ -199,7 +199,7 @@ class config extends common {
rename ('robots.txt','robots.bak');
$fileold = fopen('robots.bak','r');
$filenew = fopen('robots.txt','w');
while(!feof($fileold)) {
while(!feof($fileold)) {
$data = fgets($fileold);
if (strpos($data,'sitemap.xml') == 0) {
fwrite($filenew, $data);
@ -221,11 +221,11 @@ class config extends common {
public function backup() {
// Soumission du formulaire
if($this->isPost()) {
// Creation du ZIP
// Creation du ZIP
$filter = $this->getInput('configBackupOption',helper::FILTER_BOOLEAN) === true ? ['backup','tmp'] : ['backup','tmp','file'];
$fileName = helper::autoBackup(self::TEMP_DIR,$filter);
// Téléchargement du ZIP
// Téléchargement du ZIP
header('Content-Type: application/zip');
header('Content-Disposition: attachment; filename="' . $fileName . '"');
header('Content-Length: ' . filesize(self::TEMP_DIR . $fileName));
@ -249,18 +249,18 @@ class config extends common {
* https://www.codexworld.com/capture-screenshot-website-url-php-google-api/
*/
public function configMetaImage() {
// fonction désactivée pour un site local
if ( strpos(helper::baseUrl(false),'localhost') > 0 OR strpos(helper::baseUrl(false),'127.0.0.1') > 0) {
// fonction désactivée pour un site local
if ( strpos(helper::baseUrl(false),'localhost') > 0 OR strpos(helper::baseUrl(false),'127.0.0.1') > 0) {
$site = 'https://zwiicms.com/'; } else {
$site = helper::baseUrl(false); }
$success= false;
$googlePagespeedData = helper::urlGetContents('https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url='. $site .'&screenshot=true');
if ($googlePagespeedData !== false) {
$googlePagespeedData = json_decode($googlePagespeedData, true);
$data = str_replace('_','/',$googlePagespeedData['lighthouseResult']['audits']['final-screenshot']['details']['data']);
$data = str_replace('-','+',$data);
$img = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data));
$img = base64_decode(preg_replace('#^data:image/\w+;base64,#i', '', $data));
// Effacer la miniature
if (file_exists(self::FILE_DIR.'thumb/screenshot.jpg')) {
unlink (self::FILE_DIR.'thumb/screenshot.jpg');
@ -274,7 +274,7 @@ class config extends common {
'redirect' => helper::baseUrl() . 'config',
'state' => $success
]);
}
}
/**
* Procédure d'importation
@ -296,7 +296,7 @@ class config extends common {
]);
}
$successOpen = $zip->open(self::FILE_DIR . 'source/' . $fileZip);
if ($successOpen === FALSE) {
if ($successOpen === FALSE) {
// Valeurs en sortie erreur
$this->addOutput([
'notification' => 'Impossible de lire l\'archive',
@ -305,29 +305,29 @@ class config extends common {
]);
}
// Lire le contenu de l'archive dans le tableau files
for( $i = 0; $i < $zip->numFiles; $i++ ){
$stat = $zip->statIndex( $i );
$files [] = ( basename( $stat['name'] ));
for( $i = 0; $i < $zip->numFiles; $i++ ){
$stat = $zip->statIndex( $i );
$files [] = ( basename( $stat['name'] ));
}
// Détermination de la version à installer
if (in_array('theme.json',$files) === true &&
in_array('core.json',$files) === true &&
in_array ('user.json', $files) === false ) {
if (in_array('theme.json',$files) === true &&
in_array('core.json',$files) === true &&
in_array ('user.json', $files) === false ) {
// V9 pas de fichier user dans l'archive
// Stocker le choix de conserver les users installées
$version = '9';
} elseif (in_array('theme.json',$files) === true &&
in_array('core.json',$files) === true &&
in_array ('user.json', $files) === true &&
} elseif (in_array('theme.json',$files) === true &&
in_array('core.json',$files) === true &&
in_array ('user.json', $files) === true &&
in_array ('config.json', $files) === true ) {
// V10 valide
$version = '10';
// Option active, les users sont stockées
if ($this->getInput('configManageImportUser', helper::FILTER_BOOLEAN) === true ) {
$users = $this->getData(['user']);
}
if ($this->getInput('configManageImportUser', helper::FILTER_BOOLEAN) === true ) {
$users = $this->getData(['user']);
}
} else { // Version invalide
// Valeurs en sortie erreur
$this->addOutput([
@ -343,35 +343,35 @@ class config extends common {
$_SESSION['KEEP_USERS'] = $this->getInput('configManageImportUser', helper::FILTER_BOOLEAN);
}
// Extraire le zip ou 'site/'
$success = $zip->extractTo( 'site/' );
// Fermer l'archive
$success = $zip->extractTo( 'site/' );
// Fermer l'archive
$zip->close();
// Restaurer les users originaux d'une v10 si option cochée
if (!empty($users) &&
$version === '10' &&
$this->getInput('configManageImportUser', helper::FILTER_BOOLEAN) === true) {
$this->setData(['user',$users]);
$this->getInput('configManageImportUser', helper::FILTER_BOOLEAN) === true) {
$this->setData(['user',$users]);
}
/*
if ($version === '9' ) {
$this->importData($this->getInput('configManageImportUser', helper::FILTER_BOOLEAN));
$this->importData($this->getInput('configManageImportUser', helper::FILTER_BOOLEAN));
$this->setData(['core','dataVersion',0]);
}*/
// Met à jours les URL dans les contenus de page
// Message de notification
$notification = $success === true ? 'Restauration réalisée avec succès' : 'Erreur inconnue';
$notification = $success === true ? 'Restauration réalisée avec succès' : 'Erreur inconnue';
$redirect = $this->getInput('configManageImportUser', helper::FILTER_BOOLEAN) === true ? helper::baseUrl() . 'config/manage' : helper::baseUrl() . 'user/login/';
// Valeurs en sortie erreur
// Valeurs en sortie erreur
$this->addOutput([
'notification' => $notification,
'redirect' =>$redirect,
'state' => $success
]);
}
}
// Valeurs en sortie
$this->addOutput([
'title' => 'Restaurer',
@ -421,9 +421,9 @@ class config extends common {
'timezone' => $this->getInput('configTimezone', helper::FILTER_STRING_SHORT, true),
'itemsperPage' => $this->getInput('configItemsperPage', helper::FILTER_INT,true),
'legalPageId' => $this->getInput('configLegalPageId'),
'metaDescription' => $this->getInput('configMetaDescription', helper::FILTER_STRING_LONG, true),
'metaDescription' => $this->getInput('configMetaDescription', helper::FILTER_STRING_LONG, true),
'title' => $this->getInput('configTitle', helper::FILTER_STRING_SHORT, true),
'autoUpdate' => helper::urlGetContents('http://zwiicms.com/update/' . common::ZWII_UPDATE_CHANNEL . '/version') === false
'autoUpdate' => helper::urlGetContents('http://zwiicms.com/update/' . common::ZWII_UPDATE_CHANNEL . '/version') === false
? false
: $this->getInput('configAutoUpdate', helper::FILTER_BOOLEAN),
'proxyType' => $this->getInput('configProxyType'),
@ -488,8 +488,8 @@ class config extends common {
'state' => true
]);
}
// Initialisation du screen
if (!file_exists(self::FILE_DIR.'source/screenshot.png')) {
// Initialisation du screen
if (!file_exists(self::FILE_DIR.'source/screenshot.jpg')) {
$this->configMetaImage();
}
// Valeurs en sortie
@ -507,8 +507,8 @@ class config extends common {
file_put_contents(self::DATA_DIR . 'head.inc.html',$this->getInput('configScriptHead',null));
}
if ($this->geturl(2) === 'body') {
file_put_contents(self::DATA_DIR . 'body.inc.html',$this->getInput('configScriptBody',null));
}
file_put_contents(self::DATA_DIR . 'body.inc.html',$this->getInput('configScriptBody',null));
}
// Valeurs en sortie
$this->addOutput([
'notification' => 'Modifications enregistrées',
@ -529,17 +529,17 @@ class config extends common {
/**
* Met à jour les données de site avec l'adresse trannsmise
*/
public function updateBaseUrl () {
public function updateBaseUrl () {
// Supprimer l'information de redirection
$old = str_replace('?','',$this->getData(['core', 'baseUrl']));
$new = helper::baseUrl(false,false);
$c3 = 0;
$success = false ;
// Boucler sur les pages
// Boucler sur les pages
foreach($this->getHierarchy(null,null,null) as $parentId => $childIds) {
$content = $this->getData(['page',$parentId,'content']);
$replace = str_replace( 'href="' . $old , 'href="'. $new , stripslashes($content),$c1) ;
$replace = str_replace( 'src="' . $old , 'src="'. $new , stripslashes($replace),$c2) ;
$replace = str_replace( 'href="' . $old , 'href="'. $new , stripslashes($content),$c1) ;
$replace = str_replace( 'src="' . $old , 'src="'. $new , stripslashes($replace),$c2) ;
if ($c1 > 0 || $c2 > 0) {
$success = true;
@ -548,21 +548,21 @@ class config extends common {
}
foreach($childIds as $childId) {
$content = $this->getData(['page',$childId,'content']);
$replace = str_replace( 'href="' . $old , 'href="'. $new , stripslashes($content),$c1) ;
$replace = str_replace( 'src="' . $old , 'src="'. $new , stripslashes($replace),$c2) ;
$replace = str_replace( 'href="' . $old , 'href="'. $new , stripslashes($content),$c1) ;
$replace = str_replace( 'src="' . $old , 'src="'. $new , stripslashes($replace),$c2) ;
if ($c1 > 0 || $c2 > 0) {
$success = true;
$this->setData(['page',$childId,'content', $replace ]);
$c3 += $c1 + $c2;
}
}
}
}
// Traiter les modules dont la redirection
$content = $this->getdata(['module']);
$replace = $this->recursive_array_replace('href="' . $old , 'href="'. $new, $content, $c1);
$replace = $this->recursive_array_replace('src="' . $old , 'src="'. $new, $replace, $c2);
if ($content !== $replace) {
$this->setdata(['module',$replace]);
$this->setdata(['module',$replace]);
$c3 += $c1 + $c2;
$success = true;
}
@ -584,14 +584,14 @@ class config extends common {
* @param int count nombres d'occurences
* @return array avec les valeurs remplacées.
*/
private function recursive_array_replace ($find, $replace, $array, &$count) {
private function recursive_array_replace ($find, $replace, $array, &$count) {
if (!is_array($array)) {
return str_replace($find, $replace, $array, $count);
return str_replace($find, $replace, $array, $count);
}
$newArray = [];
foreach ($array as $key => $value) {
$newArray[$key] = $this->recursive_array_replace($find, $replace, $value,$c);
$newArray[$key] = $this->recursive_array_replace($find, $replace, $value,$c);
$count += $c;
}
return $newArray;

View File

@ -13,7 +13,7 @@
'href' => helper::baseUrl() . 'config/backup',
'value' => 'Sauvegarder',
'ico' => 'download'
]); ?>
]); ?>
</div>
<div class="col2">
<?php echo template::button('configManageButton', [
@ -21,7 +21,7 @@
'value' => 'Restaurer',
'ico' => 'upload'
]); ?>
</div>
</div>
<div class="col2">
<?php echo template::submit('configSubmit'); ?>
</div>
@ -32,7 +32,7 @@
<h4>Informations générales</h4>
<div class="row">
<div class="col4">
<?php
<?php
$pages = $this->getData(['page']);
foreach($pages as $page => $pageId) {
if ($this->getData(['page',$page,'block']) === 'bar' ||
@ -51,7 +51,7 @@
'value' => $this->getData(['config', 'title']),
'help' => 'Il apparaît dans la barre de titre et les partages sur les réseaux sociaux.'
]); ?>
</div>
</div>
</div>
<?php echo template::textarea('configMetaDescription', [
'label' => 'Description du site',
@ -59,7 +59,7 @@
'help' => 'Elle apparaît dans les partages sur les réseaux sociaux.'
]); ?>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col12">
@ -100,55 +100,55 @@
'label' => 'Fuseau horaire',
'selected' => $this->getData(['config', 'timezone']),
'help' => 'Le fuseau horaire est utile au bon référencement'
]); ?>
]); ?>
</div>
<div class="col6">
<?php $listePageId = array_merge(['' => 'Sélectionner'] , helper::arrayCollumn($this->getData(['page']), 'title', 'SORT_ASC') );
<?php $listePageId = array_merge(['' => 'Sélectionner'] , helper::arrayCollumn($this->getData(['page']), 'title', 'SORT_ASC') );
?>
<?php echo template::select('configLegalPageId', $listePageId , [
'label' => 'Mentions légales',
'selected' => $this->getData(['config', 'legalPageId']),
'help' => 'Les mentions légales sont obligatoires en France'
]); ?>
</div>
</div>
<div class="row">
</div>
</div>
<div class="row">
<div class="col6">
<?php echo template::checkbox('configCookieConsent', true, 'Message de consentement aux cookies', [
'checked' => $this->getData(['config', 'cookieConsent'])
]); ?>
</div>
</div>
<div class="col6">
<?php echo template::checkbox('rewrite', true, 'Réécriture d\'URL', [
'checked' => helper::checkRewrite(),
'help' => 'Vérifiez d\'abord que votre serveur l\'autorise : ce n\'est pas le cas chez Free.'
]); ?>
</div>
</div>
<div class="row">
<div class="col6">
<?php echo template::checkbox('configAutoBackup', true, 'Sauvegarde automatique quotidienne', [
'checked' => $this->getData(['config', 'autoBackup']),
'help' => '<p>Une archive contenant le dossier /site/data est copiée dans le dossier \'site/backup\'. La sauvegarde est conservée pendant 30 jours.</p><p>Les fichiers du site ne sont pas sauvegardés automatiquement.</p>'
]); ?>
</div>
<div class="col6">
<?php echo template::checkbox('configMaintenance', true, 'Site en maintenance', [
'checked' => $this->getData(['config', 'maintenance'])
]); ?>
</div>
</div>
<div class="row">
<div class="col3">
<div class="col6">
<?php echo template::checkbox('configAutoBackup', true, 'Sauvegarde automatique quotidienne', [
'checked' => $this->getData(['config', 'autoBackup']),
'help' => '<p>Une archive contenant le dossier /site/data est copiée dans le dossier \'site/backup\'. La sauvegarde est conservée pendant 30 jours.</p><p>Les fichiers du site ne sont pas sauvegardés automatiquement.</p>'
]); ?>
</div>
<div class="col6">
<?php echo template::checkbox('configMaintenance', true, 'Site en maintenance', [
'checked' => $this->getData(['config', 'maintenance'])
]); ?>
</div>
</div>
<div class="row">
<div class="col3">
<?php echo template::checkbox('configAutoUpdate', true, 'Mise à jour automatique', [
'checked' => $this->getData(['config', 'autoUpdate']),
'help' => 'Vérifie une fois par jour l\'existence d\'une mise à jour.',
'disabled' => !$error
]); ?>
</div>
</div>
<div class="col3">
<?php echo template::button('configUpdateForced', [
'class' => 'buttonRed',
'class' => 'buttonRed',
'ico' => 'download-cloud',
'href' => helper::baseUrl() . 'install/update',
'value' => 'Mise à jour manuelle',
@ -156,7 +156,7 @@
]); ?>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
@ -171,14 +171,14 @@
'value' => $this->getData(['config', 'social', 'facebookId'])
]); ?>
</div>
<div class="col6">
<div class="col6">
<?php echo template::text('configSocialInstagramId', [
'help' => 'Saisissez votre ID : https://www.instagram.com/[ID].',
'label' => 'Instagram',
'value' => $this->getData(['config', 'social', 'instagramId'])
]); ?>
</div>
</div>
</div>
<div class="row">
<div class="col6">
<?php echo template::text('configSocialYoutubeId', [
@ -186,16 +186,16 @@
'label' => 'Chaîne Youtube',
'value' => $this->getData(['config', 'social', 'youtubeId'])
]); ?>
</div>
</div>
<div class="col6">
<?php echo template::text('configSocialYoutubeUserId', [
'help' => 'Saisissez votre ID Utilisateur : https://www.youtube.com/user/[ID].',
'label' => 'Youtube',
'value' => $this->getData(['config', 'social', 'youtubeUserId'])
]); ?>
</div>
</div>
</div>
<div class="row">
<div class="row">
<div class="col6">
<?php echo template::text('configSocialTwitterId', [
'help' => 'Saisissez votre ID : https://twitter.com/[ID].',
@ -209,21 +209,21 @@
'label' => 'Pinterest',
'value' => $this->getData(['config', 'social', 'pinterestId'])
]); ?>
</div>
</div>
<div class="col6">
<?php echo template::text('configSocialLinkedinId', [
'help' => 'Saisissez votre ID Linkedin : https://fr.linkedin.com/in/[ID].',
'label' => 'Linkedin',
'value' => $this->getData(['config', 'social', 'linkedinId'])
]); ?>
</div>
</div>
<div class="col6">
<?php echo template::text('configSocialGithubId', [
'help' => 'Saisissez votre ID Github : https://github.com/[ID].',
'label' => 'Github',
'value' => $this->getData(['config', 'social', 'githubId'])
]); ?>
</div>
</div>
</div>
</div>
</div>
@ -233,7 +233,7 @@
<div class="block">
<h4>Référencement</h4>
<div class="row">
<div class="col6">
<div class="col6">
<?php echo template::button('configMetaImage', [
'href' => helper::baseUrl() . 'config/configMetaImage',
'value' => 'Capture Open Graph',
@ -250,10 +250,10 @@
</div>
<div class="row">
<div class="col8 offset2 textAlignCenter">
<img src="<?php echo helper::baseUrl(false) . self::FILE_DIR.'source/screenshot.jpg';?>" data-tippy-content="Cette capture d'écran est nécessaire aux partages sur les réseaux sociaux. Elle est régénérée lorsque le fichier 'screenshot.png' est effacé du gestionnaire de fichiers." />
<img src="<?php echo helper::baseUrl(false) . self::FILE_DIR.'source/screenshot.jpg';?>" data-tippy-content="Cette capture d'écran est nécessaire aux partages sur les réseaux sociaux. Elle est régénérée lorsque le fichier 'screenshot.jpg' est effacé du gestionnaire de fichiers." />
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
@ -275,7 +275,7 @@
'value' => 'Script inséré dans head',
'ico' => 'pencil'
]); ?>
</div>
</div>
<div class="col3 offset1 verticalAlignBottom">
<?php echo template::button('scriptBody', [
'href' => helper::baseUrl() . 'config/script/body',
@ -285,19 +285,19 @@
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Paramètres réseaux</h4>
<div class="row">
<div class="row">
<div class="col2">
<?php echo template::select('configProxyType', $module::$proxyType, [
'label' => 'Type de proxy',
'selected' => $this->getData(['config', 'proxyType'])
]); ?>
</div>
</div>
<div class="col8">
<?php echo template::text('configProxyUrl', [
'label' => 'Adresse du proxy',
@ -310,17 +310,17 @@
'label' => 'Port du proxy',
'placeholder' => '6060',
'value' => $this->getData(['config', 'proxyPort'])
]); ?>
]); ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
<h4>Paramètres de messagerie SMTP</h4>
<div class="row">
<div class="row">
<div class="col12">
<?php echo template::checkbox('configSmtpEnable', true, 'Activer SMTP', [
'checked' => $this->getData(['config', 'smtp','enable']),
@ -335,21 +335,21 @@
'label' => 'Adresse SMTP',
'placeholder' => 'smtp.fr',
'value' => $this->getData(['config', 'smtp','host'])
]); ?>
</div>
]); ?>
</div>
<div class="col2">
<?php echo template::text('configSmtpPort', [
'label' => 'Port SMTP',
'placeholder' => '589',
'value' => $this->getData(['config', 'smtp','port'])
]); ?>
]); ?>
</div>
<div class="col2">
<?php echo template::select('configSmtpAuth', $module::$SMTPauth, [
'label' => 'Authentification',
'selected' => $this->getData(['config', 'smtp','auth'])
]); ?>
</div>
]); ?>
</div>
</div>
<div id="configSmtpAuthParam">
<div class="row">
@ -357,27 +357,27 @@
<?php echo template::text('configSmtpUsername', [
'label' => 'Nom utilisateur',
'value' => $this->getData(['config', 'smtp','username' ])
]); ?>
]); ?>
</div>
<div class="col5">
<?php echo template::password('configSmtpPassword', [
'label' => 'Mot de passe',
'autocomplete' => 'off',
'value' => helper::decrypt ($this->getData(['config', 'smtp','username' ]),$this->getData(['config','smtp','password']))
]); ?>
]); ?>
</div>
<div class="col2">
<?php echo template::select('configSmtpSecure', $module::$SMTPEnc , [
'label' => 'Sécurité',
'selected' => $this->getData(['config', 'smtp','secure'])
]); ?>
</div>
</div>
]); ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col12">
<div class="block">
@ -388,7 +388,7 @@
'label' => 'ZwiiCMS',
'readonly' => true,
'value' => common::ZWII_VERSION
]); ?>
]); ?>
</div>
<div class="col2">
<?php echo template::text('moduleBlogVersion', [
@ -424,8 +424,8 @@
'readonly' => true,
'value' => redirection::REDIRECTION_VERSION
]); ?>
</div>
</div>
</div>
</div>
</div>
</div>
</div>