From d2ecb64646916e020c7bf8fb047e01c37c893143 Mon Sep 17 00:00:00 2001 From: Cerdic <cedric@yterium.com> Date: Thu, 9 Sep 2010 17:40:24 +0000 Subject: [PATCH] En attendant une vrai refonte des logos, moderniser le formulaire d'edition des logo en passant en CVT, puisque tout etait presque pret dans le plugin ajaxforms Evacuation du code mort dans inc/iconifier --- .gitattributes | 4 + ecrire/inc/iconifier.php | 137 +---------------- prive/editer/logo.html | 8 + prive/formulaires/editer_logo.html | 64 ++++++++ prive/formulaires/editer_logo.php | 178 +++++++++++++++++++++++ prive/style_prive_formulaires.html | 11 +- prive/themes/spip/images/reaction-48.png | Bin 0 -> 1500 bytes 7 files changed, 267 insertions(+), 135 deletions(-) create mode 100644 prive/editer/logo.html create mode 100644 prive/formulaires/editer_logo.html create mode 100644 prive/formulaires/editer_logo.php create mode 100644 prive/themes/spip/images/reaction-48.png diff --git a/.gitattributes b/.gitattributes index e56fa239f9..64e7721cf3 100644 --- a/.gitattributes +++ b/.gitattributes @@ -447,6 +447,7 @@ prive/editer/article.html -text prive/editer/auteur.html -text prive/editer/breve.html -text prive/editer/groupe_mot.html -text +prive/editer/logo.html -text prive/editer/mot.html -text prive/editer/rubrique.html -text prive/editer/site.html -text @@ -465,6 +466,8 @@ prive/formulaires/editer_breve.html -text prive/formulaires/editer_breve.php -text prive/formulaires/editer_groupe_mot.html -text prive/formulaires/editer_groupe_mot.php -text +prive/formulaires/editer_logo.html -text +prive/formulaires/editer_logo.php -text prive/formulaires/editer_mot.html -text prive/formulaires/editer_mot.php -text prive/formulaires/editer_rubrique.html -text @@ -1001,6 +1004,7 @@ prive/themes/spip/images/puce-refuser-8.png -text prive/themes/spip/images/puce-supprimer-8.png -text prive/themes/spip/images/racine-16.png -text prive/themes/spip/images/racine-24.png -text +prive/themes/spip/images/reaction-48.png -text prive/themes/spip/images/referer-16.png -text prive/themes/spip/images/referer-24.png -text prive/themes/spip/images/reseau-16.png -text diff --git a/ecrire/inc/iconifier.php b/ecrire/inc/iconifier.php index e6a80a0c5c..5fe2393607 100644 --- a/ecrire/inc/iconifier.php +++ b/ecrire/inc/iconifier.php @@ -25,142 +25,15 @@ $logo_libelles['id_racine'] = _T('logo_standard_rubrique')." ".aide ("rublogo"); // http://doc.spip.org/@inc_iconifier_dist function inc_iconifier_dist($id_objet, $id, $script, $visible=false, $flag_modif=true) { - if ($GLOBALS['spip_display'] == 4) return ""; - - $logo_libelles = array( - 'id_article' => _T('logo_article').aide("logoart"), - 'id_auteur' => _T('logo_auteur').aide("logoart"), - 'id_breve' => _T('logo_breve').aide("breveslogo"), - 'id_syndic' => _T('logo_site')." ".aide("rublogo"), - 'id_mot' => _T('logo_mot_cle').aide("breveslogo"), - 'id_groupe' => _T('logo_groupe').aide("breveslogo"), - 'id_rubrique'=> _T('logo_rubrique')." ".aide("rublogo"), - 'id_racine' => _T('logo_standard_rubrique')." ".aide("rublogo") - ); - - $texteon = $logo_libelles[($id OR $id_objet != 'id_rubrique') ? $id_objet : 'id_racine']; - + global $logo_libelles; $chercher_logo = charger_fonction('chercher_logo', 'inc'); - // Add the redirect url when uploading via iframe - $iframe_script = generer_url_ecrire('iconifier',"type=$id_objet&$id_objet=$id&script=$script",true); - $iframe = "<input type='hidden' name='iframe_redirect' value='".rawurlencode($iframe_script)."' />\n"; - - $logo = $chercher_logo($id, $id_objet, 'on'); - $logo_s = $chercher_logo($id, $id_objet, 'off'); - if (!$logo) { - if ($flag_modif - AND $GLOBALS['meta']['activer_logos'] != 'non') { - $masque = indiquer_logo($texteon, $id_objet, 'on', $id, $script, $iframe); - $masque = "<div class='cadre_padding'>$masque</div>"; - $bouton = bouton_block_depliable($texteon, $visible, "on-$id_objet-$id"); - $res = debut_block_depliable($visible,"on-$id_objet-$id") . $masque . fin_block(); - } - } else { - list($img, $clic) = decrire_logo($id_objet,'on',$id, 170, 170, $logo, $texteon, $script, $flag_modif AND !$logo_s); - - $bouton = bouton_block_depliable($texteon, $visible, "on-$id_objet-$id"); - - $survol = ''; - $texteoff = _T('logo_survol'); - if (!$logo = $logo_s) { - if ($flag_modif AND $GLOBALS['meta']['activer_logos_survol'] == 'oui') { - $masque = "<br />".indiquer_logo($texteoff, $id_objet, 'off', $id, $script, $iframe); - $survol .= "<br />".block_parfois_visible("off-$id_objet-$id", $texteoff, $masque, null, $visible); - } - $masque = debut_block_depliable($visible,"on-$id_objet-$id") - . "<div class='cadre_padding'>" - . $clic . $survol - . "</div>" - . fin_block(); - } else { - list($imgoff, $clicoff) = decrire_logo($id_objet, 'off', $id, 170, 170, $logo, $texteoff, $script, $flag_modif); - $masque = debut_block_depliable($visible, "off-$id_objet-$id") . $clicoff . fin_block(); - $survol .= "<br />".bouton_block_depliable($texteoff, $visible, "off-$id_objet-$id") - . "<div class='cadre_padding'>".$imgoff.$masque."</div>"; - $masque = debut_block_depliable($visible,"on-$id_objet-$id") . $clic . fin_block() . $survol; - } - - $res = "$img$masque"; - } - - if ($res) { - $res = debut_cadre('r', 'image-24.gif', '', $bouton, '', '', false) - . $res - . fin_cadre_relief(true); - - if (_request("exec") != "iconifier") { - $js.= http_script('', 'async_upload.js') - . http_script('$("form.form_upload_icon").async_upload(async_upload_icon)'); - } - else - $js = ""; - return ajax_action_greffe("iconifier", $id, $res).$js; - } - else - return ''; - -} - - -// http://doc.spip.org/@indiquer_logo -function indiquer_logo($titre, $id_objet, $mode, $id, $script, $iframe_script) { - - global $formats_logos; - $afficher = ""; - $reg = '[.](' . join('|', $formats_logos) . ')$'; - - $afficher = "\n<label for='image'>" . - _T('info_telecharger_nouveau_logo') . - "</label><br />" . - "\n<input name='image' id='image' type='file' class='forml spip_xx-small' size='15' />" . - "<div style='text-align: " . $GLOBALS['spip_lang_right'] . "'>" . - "\n<input name='sousaction1' type='submit' value='" . - _T('bouton_telecharger') . - "' class='fondo spip_xx-small' /></div>" . - $afficher; - - $type = type_du_logo($id_objet); - return redirige_action_post('iconifier', - "$id+$type$mode$id", - $script, - "$id_objet=$id", - $iframe_script.$afficher, - " enctype='multipart/form-data' class='form_upload_icon'"); -} - -// http://doc.spip.org/@decrire_logo -function decrire_logo($id_objet, $mode, $id, $width, $height, $img, $titre="", $script="", $flag_modif=true) { - - list($fid, $dir, $nom, $format, $timestamp) = $img; - include_spip('inc/filtres_images_mini'); - - $res = image_reduire("<img src='$fid' alt='' class='miniature_logo' />", $width, $height); + $texteon = $logo_libelles[($id OR $id_objet != 'id_rubrique') ? $id_objet : 'id_racine']; + $objet = substr($id_objet,3); - if ($res){ - $src = extraire_attribut($res,'src'); - $res = inserer_attribut($res, 'src', "$src?$timestamp"); - $res = "<div><a href='" . $fid . "'>$res</a></div>"; - } - else - $res = "<img src='$fid?$timestamp' width='$width' height='$height' alt=\"" . htmlentities($titre) . '" />'; - if ($taille = @getimagesize($fid)) - $taille = _T('info_largeur_vignette', - array('largeur_vignette' => $taille[0], - 'hauteur_vignette' => $taille[1]) - ); + $img = balise_img(chemin_image('image-24.png'), "", 'cadre-icone'); + return recuperer_fond('prive/editer/logo',array('objet'=>$objet,'id_objet'=>$id, 'titre'=>$img.$texteon)); - return array($res, - "<div class='spip_xx-small'>" . $taille - . ($flag_modif - ? "\n<br />[" - . ajax_action_auteur("iconifier", "$id-$nom.$format", - $script, "$id_objet=$id&type=$id_objet", - array(_T('lien_supprimer')), - '',"function(r,status) {this.innerHTML = r; \$('form.form_upload_icon',this).async_upload(async_upload_icon);}") ."]" - : '' - ) - . "</div>"); } ?> diff --git a/prive/editer/logo.html b/prive/editer/logo.html new file mode 100644 index 0000000000..d519e4f9de --- /dev/null +++ b/prive/editer/logo.html @@ -0,0 +1,8 @@ +[(#REM) + + Un petit descriptif ne serait pas superflu + +] +<div class="ajax"> +#FORMULAIRE_EDITER_LOGO{#ENV{objet,''},#ENV{id_objet,''},#ENV{redirect,''},#ENV**} +</div> diff --git a/prive/formulaires/editer_logo.html b/prive/formulaires/editer_logo.html new file mode 100644 index 0000000000..60a123fb95 --- /dev/null +++ b/prive/formulaires/editer_logo.html @@ -0,0 +1,64 @@ +#CACHE{0} +<div class='formulaire_spip formulaire_editer formulaire_editer_logo formulaire_editer_logo_#ENV{objet}'> + [<h3 class="titrem">(#ENV{_options}|table_valeur{titre})</h3>] + [<p class="reponse_formulaire reponse_formulaire_ok">(#ENV*{message_ok})</p>] + [<p class="reponse_formulaire reponse_formulaire_erreur">(#ENV*{message_erreur})</p>] + [(#ENV{editable}) + #SET{valider,''} + <form method='post' action='#ENV{action}' enctype='multipart/form-data'><div> + [(#REM) declarer les hidden qui declencheront le service du formulaire + parametre : url d'action ] + #ACTION_FORMULAIRE{#ENV{action}} + [(#REM) un submit pour attraper la touche entree] + <div style="display:none;"><input type='submit' class='submit' value='<:bouton_telecharger:>' /></div> + <ul> + <li class="editer_logo_on [ (#ENV**{erreurs}|table_valeur{logo_on}|oui)erreur]"> + [(#ENV{logo_on}|oui) + <div class="apercu"> + [<div class="spip_logos">(#ENV{logo_on}|image_reduire{[(#ENV{_options}|table_valeur{image_reduire}|sinon{170})]}|inserer_attribut{alt,logo_on})</div>] + #SET{largeur,#ENV{logo_on}|largeur} + #SET{hauteur,#ENV{logo_on}|hauteur} + <div class="taille"><:info_largeur_vignette{largeur_vignette=#GET{largeur},hauteur_vignette=#GET{hauteur}}:></div> + [(#ENV{logo_off}|non) + <input type='submit' class='submit supprimer' id="supprimer_logo_on_#ENV{objet}_#ENV{id_objet}" name="supprimer_logo_on" value='<:lien_supprimer|ucfirst|attribut_html:>' /> + ] + </div> + ][(#ENV{logo_on}|non) + <label for="logo_on_#ENV{objet}_#ENV{id_objet}">[(#ENV{_options}|table_valeur{label}|sinon{<:info_telecharger_nouveau_logo:>})]</label>[ + <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{logo_on})</span> + ]<input type='file' class='file' name='logo_on' size="[(#ENV{_options}|table_valeur{size_input}|sinon{15})]" id='logo_on_#ENV{objet}_#ENV{id_objet}' value="" /> + #SET{valider,' '} + ] + </li> + [(#ENV{logo_survol}|ou{#ENV{logo_off}}|oui) + <li class="editer_logo_off [ (#ENV**{erreurs}|table_valeur{logo_off}|oui)erreur]"> + [(#ENV{logo_off}|oui) + <div class="apercu"> + <:logo_survol:> + [<div class="spip_logos">(#ENV{logo_off}|image_reduire{[(#ENV{_options}|table_valeur{image_reduire}|sinon{170})]}|inserer_attribut{alt,logo_off})</div>] + #SET{largeur,#ENV{logo_off}|largeur} + #SET{hauteur,#ENV{logo_off}|hauteur} + <div class="taille"><:info_largeur_vignette{largeur_vignette=#GET{largeur},hauteur_vignette=#GET{hauteur}}:></div> + <input type='submit' class='submit supprimer' id="supprimer_logo_off_#ENV{objet}_#ENV{id_objet}" name="supprimer_logo_off" value='<:lien_supprimer|ucfirst|attribut_html:>' /> + </div> + ][(#ENV{logo_off}|non) + <div [(#ENV**{erreurs}|table_valeur{logo_off}|non) + class="ajouter_survol"><a href="#" onclick="jQuery(this).parent().siblings().show().parents('form').find('.boutons').show();return false;"><:logo_survol:></a></div> + <div style="display:none;" #SET{hide,' '}]> + <label for="logo_off"><:info_telecharger_nouveau_logo:></label>[ + <span class='erreur_message'>(#ENV**{erreurs}|table_valeur{logo_off})</span> + ]<input type='file' class='file' name='logo_off' size="15" id='logo_off_#ENV{objet}_#ENV{id_objet}' value="" /> + #SET{valider,' '} + </div> + ] + </li> + ] + </ul> + [(#REM) ajouter les saisies supplementaires : extra et autre, a cet endroit ] + <!--extra--> + [(#GET{valider}) + <p class="boutons"[(#GET{hide})style='display:none;']><input type='submit' class='submit' value='<:bouton_telecharger:>' /></p> + ] + </div></form> + ] +</div> diff --git a/prive/formulaires/editer_logo.php b/prive/formulaires/editer_logo.php new file mode 100644 index 0000000000..7dd165cc75 --- /dev/null +++ b/prive/formulaires/editer_logo.php @@ -0,0 +1,178 @@ +<?php + +/***************************************************************************\ + * SPIP, Systeme de publication pour l'internet * + * * + * Copyright (c) 2001-2010 * + * Arnaud Martin, Antoine Pitrou, Philippe Riviere, Emmanuel Saint-James * + * * + * Ce programme est un logiciel libre distribue sous licence GNU/GPL. * + * Pour plus de details voir le fichier COPYING.txt ou l'aide en ligne. * +\***************************************************************************/ + +if (!defined("_ECRIRE_INC_VERSION")) return; + +/** + * Formulaire #EDITER_LOGO + * + * Ce formulaire ajoute, modifie ou supprime des logos sur les objets de SPIP. + * - En dehors d'une boucle, ce formulaire modifie le logo du site. + * - Dans une boucle, il modifie le logo de la table selectionnee. + * Pensez juste que l'appel de #LOGO_{TYPE} s'appuie sur le nom de la cle primaire et non sur le + * nom de l'objet reel. Par exemple on ecrira #LOGO_GROUPE (et non #LOGO_GROUPEMOTS) pour afficher + * un logo issu du formulaire mis dans une boucle GROUPES_MOTS + * - il est possible de lui passer les parametres objet et id : #FORMULAIRE_EDITER_LOGO{article,1} + * - il est possible de spécifier une url de redirection apres traitement : + * ex. #FORMULAIRE_EDITER_LOGO{article,1,#URL_ARTICLE} + */ + +/** + * Chargement du formulaire + * + * @param string $objet Objet SPIP auquel sera lie le document (ex. article) + * @param integer $id_objet Identifiant de l'objet + * @param string $retour Url de redirection apres traitement + * @param Array $options Tableau d'option (exemple : image_reduire => 50) + * @return Array Variables d'environnement pour le fond + */ +function formulaires_editer_logo_charger_dist($objet, $id_objet, $retour='', $options=array()){ + if (!is_array($options)) + $options = unserialize($options); + $res = array( + 'editable'=>($GLOBALS['meta']['activer_logos'] == 'oui' ? ' ' : ''), + 'logo_survol'=>($GLOBALS['meta']['activer_logos_survol'] == 'oui' ? ' ' : ''), + 'objet'=>$objet, + 'id_objet'=>$id_objet, + '_options'=>$options + ); + // pas dans une boucle ? formulaire pour le logo du site + // dans ce cas, il faut chercher un 'siteon0.ext' + if (!$objet) + $_id_objet = 'site'; + else + $_id_objet = id_table_objet($objet); + + // rechercher le logo de l'objet + // la fonction prend un parametre '_id_objet' etrange : + // le nom de la cle primaire (et non le nom de la table) + // ou directement le nom du raccourcis a chercher + $chercher_logo = charger_fonction('chercher_logo', 'inc'); + $etats = $res['logo_survol'] ? array('on','off') : array('on'); + foreach($etats as $etat) { + $logo = $chercher_logo($id_objet, $_id_objet, $etat); + if ($logo){ + $res['logo_'.$etat] = $logo[0]; + } + } + // pas de logo_on -> pas de formulaire pour le survol + if (!isset($res['logo_on'])) + $res['logo_survol']=''; + + return $res; +} + +/** + * Verification avant traitement + * + * On verifie que l'upload s'est bien passe et + * que le document recu est une image (d'apres son extension) + * + * @param string $objet + * @param integer $id_objet + * @param string $retour + * @return Array Tableau des erreurs + */ +function formulaires_editer_logo_verifier_dist($objet, $id_objet, $retour=''){ + $erreurs = array(); + // verifier les extensions + $sources = formulaire_editer_logo_get_sources(); + foreach($sources as $etat=>$file) { + // seulement si une reception correcte a eu lieu + if ($file AND $file['error'] == 0) { + if (!in_array(strtolower(pathinfo($file['name'], PATHINFO_EXTENSION)),array('jpg','png','gif','jpeg'))) + $erreurs['logo_'.$etat] = _L('Extension non reconnue'); + } + } + return $erreurs; +} + +/** + * Traitement de l'upload d'un logo + * + * Il est affecte au site si la balise n'est pas dans une boucle, + * sinon a l'objet concerne par la boucle ou indiquee par les parametres d'appel + * + * @param string $objet + * @param integer $id_objet + * @param string $retour + * @return Array + */ +function formulaires_editer_logo_traiter_dist($objet, $id_objet, $retour=''){ + $res = array('editable'=>' '); + + // pas dans une boucle ? formulaire pour le logo du site + // dans ce cas, il faut chercher un 'siteon0.ext' + if (!$objet) + $_id_objet = 'site'; + else + $_id_objet = id_table_objet($objet); + + // supprimer l'ancien logo puis copier le nouveau + include_spip('inc/chercher_logo'); + include_spip('inc/flock'); + $type = type_du_logo($_id_objet); + $chercher_logo = charger_fonction('chercher_logo','inc'); + + // effectuer la suppression si demandee d'un logo + $on = _request('supprimer_logo_on'); + if ($on OR _request('supprimer_logo_off')){ + $logo = $chercher_logo($id_objet, $_id_objet, $on ? 'on' : 'off'); + if ($logo) + spip_unlink($logo[0]); + $res['message_ok'] = ''; // pas besoin de message : la validation est visuelle + } + + // sinon supprimer ancien logo puis copier le nouveau + else { + include_spip('action/iconifier'); + $ajouter_image = charger_fonction('spip_image_ajouter','action'); + $sources = formulaire_editer_logo_get_sources(); + foreach($sources as $etat=>$file) { + if ($file and $file['error']==0) { + $logo = $chercher_logo($id_objet, $_id_objet, $etat); + if ($logo) + spip_unlink($logo[0]); + $ajouter_image($type.$etat.$id_objet," ",$file); + $res['message_ok'] = ''; // pas besoin de message : la validation est visuelle + } + } + } + + if ($retour){ + include_spip('inc/headers'); + $res['redirect'] = parametre_url($retour,'var_mode','calcul'); + } + + return $res; +} + + +/** + * Extraction des sources des fichiers uploades correspondant aux 2 logos (normal + survol) + * si leur upload s'est bien passé + * + * @return Array + */ +function formulaire_editer_logo_get_sources(){ + if (!$_FILES) $_FILES = $GLOBALS['HTTP_POST_FILES']; + if (!is_array($_FILES)) return array(); + + $sources = array(); + foreach(array('on','off') as $etat) { + if ($_FILES['logo_'.$etat]['error'] == 0) { + $sources[$etat] = $_FILES['logo_'.$etat]; + } + } + return $sources; +} +?> diff --git a/prive/style_prive_formulaires.html b/prive/style_prive_formulaires.html index 143ad6b6d8..eb200c8981 100644 --- a/prive/style_prive_formulaires.html +++ b/prive/style_prive_formulaires.html @@ -501,8 +501,8 @@ padding-top:10px; * Formulaires compactes */ -.formulaire_spip_compact{ - font-size: 100%; +.formulaire_spip_compact, #navigation .formulaire_spip,#extra .formulaire_spip{ + margin-top: 20px; } .formulaire_spip_compact ul li, #navigation .formulaire_spip li,#extra .formulaire_spip li { @@ -523,7 +523,6 @@ padding-top:10px; padding-top: 3px; padding-bottom: 3px; margin-#GET{left}:0; - } .formulaire_spip_compact select,#navigation .formulaire_spip select,#extra .formulaire_spip select { font-size: 0.95em; width:auto;padding:1px 0;} @@ -563,3 +562,9 @@ input[type="submit"] { padding: 0; overflow:visible; } + +/* Cas particuliers */ +.formulaire_editer_logo {} +.formulaire_editer_logo .titrem {font-size: 1.1em;} +.formulaire_editer_logo .apercu,.formulaire_editer_logo .ajouter_survol {text-align: center;} +.formulaire_editer_logo .taille {font-size: 0.9em;} \ No newline at end of file diff --git a/prive/themes/spip/images/reaction-48.png b/prive/themes/spip/images/reaction-48.png new file mode 100644 index 0000000000000000000000000000000000000000..18ef862974ce85a1ff7f14aa4a54163c52694ce1 GIT binary patch literal 1500 zcmdUv`#aQm6vsc`xnvp)+6}o(l!kH{7A>|d#26c6TpDVONN(ja>r%2AQ$$JIEKg-K z!{Awi#K@D|7&CTsp+=;k+>@eli*?<Kou~ea{o$PV^FHTwp7YCj&Q&tWO%<(!1^}qK z6J2~1%2WgmwMCI*3S%7<0wwskIfLphy$=e5h;Z_B0-*MW^5+nw!W)DVeLMk3!6^na z0Qgr?Vom{&WC?&g7yyTS0JP}rX72-v#*ReSfJEQ8@WgW=@nL`*5*3?hL2~soIBRWT zYhml2{do)kq^-M)lV5VsEc+0V>izvADm`AEmbk6?N@BMYIU`%sIHFBj+{+n8WW^3t zB-J9b#)BU_5S6kp1I6inCR5#y?r9>U+MIk$Fj1|n-S~<Ue4*Cp?N2}3Wf<Wn3s+M` zzm2ADF7o|?u#s2&A;8@egv7QBJ`5~&PT_ZqQyfA2tcbvT@<j{449+5VjWVPV!g1P! zFBH=56cyn;Nu==!%KM9FyRiddwBsicuLcKARWX=8?St0VzMT%atm4#{ZS`b89~@DU z6b$S3U<V%P_){q5+FXcRb-Hn%!38fbFVFci@2{pN=n8ixaj`g5Bxr1GM0MC5JjjT8 zuZ6yxt!BxXm5rAgf#vzSOYqrJOgb~{oFm+^HbA9ATVMZ+D)5-9%JIz8Qs-h{UbcrM z&T#ST*T?vFc6Q0|KMsq73{Tvy^H!5Pr%DTN*ueBu0guOP8(+vP*16cb^unzF;oKIS zI2kYxx3}PJfS$fSQn}#Q$$P81fwJa(le-sNy8%5pS=$T%jBrtfsjs*YC1mj0#s-70 z4lpGY-|ieB5D40wfeT99)kRWNHDLS)54M{j95X<4bTmR4Qa1$C)6?G&x%~7uq@_jg zD`IA0vE?hGtgQSE85#=wijZ5|Q<?w}bmzX42?+@jtiVe4yfXTS9yYp=!%@|gNF;7d zgXdc5xvcO|ju%A-l<|1!57*X`rC)%wd3L%?!)X=1=D2=BbE&MNqJovv(gi2C(9q$H zcvd(fKR+MUp{=WH3NA^d(xDkN86|iB`%mv8`jI1W@slUSay8VjOm@^`WP8iP%5v`n znYOu67II*A_14bcjpotycZS%VCK{>$4u`*~<PS<Z`?p%``Q^+wt*?R5(<(bz>O&}O zD*FrK*3{qwwKyD(>y;bSTEmTw4)^QC2CGJmqdk~`y2md*dVsw3o2BK1{VlIW7n_7a z;hQo(HefSl_|2}&c~M$+glv9($#O4_u{>r=<q-x-A+A91)6o9R%uMvVwb&ZjvGY>L zj~^tT><eoB`z3L?A)=b~XSn2*vAtM$sLe=lF~mLaEQ?UGk<lZ+Hpv-ny%3ZREUQJL zP2;|%nAoTN#JHz#<03(1T%1}|>Bt3k`Fhglx28E_s}wgkx3D=Dt_CzJ<rt<=sZ`>3 z`7CpD^P`myUlk3F8b{1T#h;`>bT1J2W1C<u!Fu!Ur*qGv)6y7>p!0#IG1Yf*H&+b~ z<2-$4U@v0rRqFnM?Vkuui}RoQ*co4fo2}>3L}3uKV``yZ)G)cSFj1XaNU5R(iuOSK zYgU#&uV;CCY!3C9y*j=PEYY7qRsC>SX2fzqSjv6QEyUQtj8iebfbTHr*8u3-a&51J z;H0jKSZK`1=!^~|ma~0_VPbb;pAC#Dv*$G<nR%?LC<M5hKuS^u#)ijwQGhbZmTLl% z^ZhanP}OBGGY9O9Q=Yp)04Jf63hcIa+#&pL7OX3+Am(%!GxrWDzASKeCAm~P2VeRR Dr~H#f literal 0 HcmV?d00001 -- GitLab