KrISS feed 8.7 - Ein einfacher und schlauer (oder dummer) Feed-Reader. Von Tontof
  • Wednesday 12 August 2015 - 19:25

    Le spam devient de plus en plus problématique sur mon WordPress, je viens de dépasser les 150 000 pour le seul mois de Juillet ! J’ai beau utiliser Akismet qui accompli un très beau travail, il a le défaut de laisser les spams 15 jours dans la catégorie indésirable avant de les effacer.

    Bilan, ma base de données atteint la taille respectable de 350 Mo !!

    spam_wordpress
    Il est toujours possible de demander à WordPress de purger tous les commentaires indésirables, mais, via le moteur php, il n’en efface que 15 000 à la fois tout en laissant le serveur indisponible pendant un bon quart d’heure !

    Alors une autre méthode brutale, mais efficace. Pensez bien à faire un back-up de votre Base de Données avant !

    root@server:~# mysql -u root -p
    Enter password:
    Welcome to the MariaDB monitor.  Commands end with ; or \g.
    Your MariaDB connection id is 64670
    Server version: 10.0.21-MariaDB-1~wheezy mariadb.org binary distribution
    
    Copyright (c) 2000, 2015, Oracle, MariaDB Corporation Ab and others.
    
    Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.
    
    MariaDB [(none)]> show databases;
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    | tmp                |
    | tokudb             |
    | wpdb               |
    | wpdbpb             |
    +--------------------+
    7 rows in set (0.00 sec)
    MariaDB [(none)]> use wpdbpb;
    Reading table information for completion of table and column names
    You can turn off this feature to get a quicker startup with -A
    
    Database changed
    MariaDB [wpdbpb]> show tables;
    +---------------------------+
    | Tables_in_wpdbpb          |
    +---------------------------+
    | wp_commentmeta            |
    | wp_comments               |
    [...]
    +---------------------------+
    14 rows in set (0.00 sec)
    
    MariaDB [wpdbpb]> DELETE from wp_comments WHERE comment_approved =  'spam';
    Query OK, 35010 rows affected (0.57 sec)

    Et voilà, 35 000 spams effacés en 0,57 sec !! Imbattable.

    La table à nettoyer est wp_comment, elle a peut être été renommée par un plugin à l’aide d’un préfixe pour sécuriser WordPress. Pour résumer quelques queries utiles :
    Si vous voulez nettoyer les commentaires en attente :

    DELETE from wp_comments WHERE comment_approved =  '0';

    Si vous voulez nettoyer les commentaires en corbeille :

    DELETE from wp_comments WHERE comment_approved =  'trash';

    Si vous voulez nettoyer les commentaires en indésirables :

    DELETE from wp_comments WHERE comment_approved =  'spam';

    Éventuellement, il ne reste plus qu’à scripter rapidement quelque chose en crontab pour nettoyer périodiquement le spam.

    The post Se Débarrasser du Spam sur WordPress appeared first on Le Blog d'un Geek.

  • Monday 10 August 2015 - 20:49

    Framapack, Ninite... installent en un clin d'oeil tous les logiciels de votre choix. Sans que vous ayez à intervenir.

    Lorsque, suite à un problème quelconque, on ne peut ni réparer Windows ni restaurer les paramètres d'usine, on se trouve obligé de formater le disque dur pour installer une version propre du système d'exploitation de Microsoft. A ce stade, le plus dur reste pourtant encore à faire. Il faut, en effet, procéder à une mise à jour de Windows via Windows Update et à l'installation des pilotes de périphériques.

     

    Il faut aussi réinstaller tous les logiciels dont on se sert habituellement. Or cette phase, pourtant la plus facile car la moins technique, devient vite fastidieuse pour quiconque veut que son ordinateur couvre tous ses besoins en bureautique, Internet, multimédia, etc. Qui n'a pas perdu beaucoup de temps à installer un par un ses programmes préférés ? Qui n'a pas rêvé d'installer ces derniers en un clic ?

     

    C'est pour répondre à cette problématique que les sites ci-après ont mis au point des outils qui feront le travail à votre place. Comme au marché, vous choisissez vos logiciels, vous téléchargez l'outil proposé par le site (un fichier exécutable), le lancez, et le tour est joué : il se connecte au serveur, rapatrie vos applications et les installe automatiquement.

     

    Cerise sur le gâteau, ces services en ligne et les catalogues de logiciels proposés sont 100% gratuits.

     

     

    Les installeurs automatiques de logiciels

     

  • Monday 27 July 2015 - 16:32

    La Contre-histoire de la philosophie s'achève à l'occasion de cette treizième édition de l'Université populaire de Caen, mais celle-ci est menacée par le spectre de la... fin.

    C’est ce matin qu’a débuté la diffusion des conférences de Michel Onfray sur les ondes de France Culture. Le philosophe hédoniste y déroulera les derniers mètres du fil de sa Contre-histoire de la philosophie, une histoire alternative de la philosophie qu’il raconte avec brio depuis qu'il a fondé l'Université populaire de Caen en 2002. Et qui a fait de lui le philosophe le plus populaire de France et de Navarre.

     

    >> Lire la suite.

  • Tuesday 21 July 2015 - 19:20
  • Tuesday 21 July 2015 - 19:20

    Je vois souvent passer des questions sur le forums ou autres fils de discussion concernant la mise en production d'un projet Django.
    Ici je vais présenter une façon de faire, utilisant Nginx Gunicorn et Supervisord .

    Prérequis

    Sur une Débian toute fraiche,

    Nginx

    sudo apt-get install nginx
    

    Virtualenv

    Car nous travaillons toujours avec un environnement virtuel, dans lequel nous allons y installer les dépendances de notre projet.
    Ce qui permet de ne pas avoir de conflit de version avec d'autres éventuels projets déjà en prod.

    pip install virtualenv virtualenvwrapper
    

    Note : Si vous n'avez pas l'outil pip de disponible, installez-le comme ceci

    sudo apt-get install python-setuptools
    sudo easy_install pip
    

    Puis dans votre fichier ~/.bashrc , ajoutez les lignes suivantes, pour l'autocompletion

    export VIRTUALENVWRAPPER_VIRTUALENV_ARGS='--no-site-package'
    export WORKON_HOME=$HOME/.virtualenvs
    source /usr/local/bin/virtualenvwrapper.sh
    

    Gunicorn

    Pourquoi pas utiliser uWSGI ? humm ... car je préfère Gunicorn qui me donne toute satisfaction sur mes projets en prod. donc ... pourquoi pas !

    sudo apt-get install libevent-dev
    pip install gunicorn
    

    Supervisor

    Installation simple :

    sudo pip install supervisor
    

    Récupération du fichier de conf par défaut

    echo_supervisord_conf > /etc/supervisord.conf
    

    Dans le fichier de conf, afin de pouvoir manager votre projet via l'interface web, il faut dé-commenter et paramétrer les lignes suivantes

    [inet_http_server]         ; inet (TCP) server disabled by default
    port=*:9001        ; (ip_address:port specifier, *:port for all iface)
    username=user              ; (default is no username (open server))
    password=123               ; (default is no password (open server))
    

    Note: Changer le username et password évidemment

    L'interface web sera disponible à l'adresse : http://ipduserveur:9001

    Pour le lancement automatique au démarrage du système, vous pouvez utiliser ces scripts d'init:

    1. debian init supervisor
    2. debian init supervisor

    Installer votre projet

    Notre environnement est prêt, nous allons commencer par installer le projet Django dans l’environnement virtuel.

    Création du virtualenv

    mkvirtualenv monprojet
    

    Si vous utilisez git, cloner votre projet, sinon, copier le à l'endroit que vous souhaitez, ( pour l'exemple ce sera /var/www/monprojet )

    Installation des dépendances du projet

    si vous utilisez également les environnements virtuels pour développer ( ce que je conseille ) vous pouvez alors enregistrer la liste des libs python installées dans cette environnement, afin de pouvoir également les installer ( avec la même version ) sur un autre serveur.

    Pour avoir la liste des libs :

    pip freeze > requirements.txt
    

    puis sur votre serveur, pour installer les libs depuis un export freeze :

    pip install -r requirements.txt
    

    Configuration de Django

    Il vous faudra peut-être toucher un peu à votre fichier settings.py pour le passer du mode debug au mode production.
    Personnellement j'utilise une autre subtilité qui me permet de ne pas avoir à toucher au fichier settings.py ( j'expliquerai celà dans un autre billet ) .

    N'oubliez pas de vérifier le paramètre STATIC_ROOT

    STATIC_ROOT = '/var/www/static_monprojet/'
    

    C'est le répertoire ou seront copiés les fichiers statiques du projet, pour ensuite être servis par Nginx

    Ce répertoire DOIT EXISTER

    Une fois le répertoire créé, nous allons y "placer/lier" les fichiers statiques du projet

    python manage.py collectstatic --link
    

    Perso je préfère y mettre des liens symboliques .. ( les gouts et les couleurs ... )

    Liaison du projet avec Gunicorn

    Nous allons créer un fichier dans notre projet qui sera utilisé pour le lancement du/des process Gunicorn ( vous devrez adapter les valeurs dans ce script )

    vim /var/www/monprojet/monprojet/gunicorn.sh
    

    Et voici le contenu

    #!/bin/bash
      set -e
      NUM_WORKERS=2
      USER=www-data
      GROUP=www-data
      ADDRESS=127.0.0.1:5002
      cd /var/www/monprojet
      source /home/monuser/.virtualenvs/monprojet/bin/activate
      exec gunicorn monprojet.wsgi:application -w $NUM_WORKERS --bind=$ADDRESS \
        --user=$USER --group=$GROUP --log-level=debug
    

    Puis on le rend exécutable

    chmod 777 /var/www/monprojet/monprojet/gunicorn.sh
    

    Configuration Supervisord

    Notre projet est prêt, afin de lancer Gunicorn automatiquement, nous allons utiliser supervisord, qui en plus de s'occuper de démarrer le projet automatiquement au démarrage du système, va aussi le relancer en cas de crash, gérer les logs et vous donner la main pour arrêter ré-demarrer les process, via l'interface web ou en mode console.

    supervisord.png

    Ajoutez à la fin du fichier de configuration /etc/supervisord.conf les lignes suivantes ( paramètres à adapter selon votre cas )

    [program:guni_monprojet]
    directory=/var/www/monprojet/monprojet
    user = www-data
    autostart=true
    autorestart=true
    stdout_logfile=/var/log/monprojet.log
    redirect_stderr=true
    stopsignal=QUIT
    command = /var/www/monprojet/monprojet/monprojet.sh
    

    Ne reste plus qu'à redémarrer supervisor pour prendre en compte la nouvelle config.

    Pour le lancer manuellement

    sudo supervisord -c /etc/supervisord.conf
    

    Vhost Nginx

    Dernier point, la création du vhost de Nginx, pour diriger les requêtes vers Gunicorn qui écoute sur le port 5002 ( il est aussi possible d'utiliser un fichier socket à la place )

    vim /etc/nginx/sites-enabled/monprojet
    

    Et voilà le contenu ( fonctionnel, mais vous pouvez l'adapter )

    upstream us_monprojet {
            server 127.0.0.1:5002;
    }
    
    
    server {
            listen 80;
    
            root /var/www/monprojet;
    
            gzip             on;
            gzip_min_length  1000;
            gzip_proxied     expired no-cache no-store private auth;
            gzip_types       text/plain application/xml text/css text/javascript application/x-javascript application/x-shockwave-flash video/x-flv;
            gzip_disable     "MSIE [1-6]\.";
    
    
            server_name monprojet.com;
            charset utf-8;
    
            client_max_body_size 75M;
    
    
            location ~ /\.ht {
                deny  all;
            }
    
            location /favicon.ico {
                    alias /var/www/monprojet/monprojet/static/favicon.ico;
    
                    if (-f $request_filename) {
                            access_log off;
                            expires max;
                    }
    
            }
    
    
            location /media {
                    alias /var/www/monprojet/monprojet/media;
    
                    if (-f $request_filename) {
                            access_log off;
                            expires max;
                    }
    
            }
    
            location /static {
                    alias /var/www/static_monprojet/;
    
                    if (-f $request_filename) {
                            access_log off;
                            expires max;
                    }
    
            }
    location / {
    
                    if (-f $request_filename) {
                            access_log off;
                            expires max;
                    }       
    
                    #gunicornParams
                    if (!-f $request_filename) {
                            proxy_pass         http://us_monprojet;
                            break;
                    }       
                    proxy_redirect     off;
                    proxy_set_header   Host             $host;
                    proxy_set_header   X-Real-IP        $remote_addr;
                    proxy_set_header   X-Forwarded-For  $proxy_add_x_forwarded_for;
    
            }       
    }       
    
    

    Ne reste plus qu'à activer le vhost, et relancer nginx

    ln -s /etc/nginx/sites-available/monprojet /etc/nginx/sites-enabled/
    service nginx reload
    
  • Monday 20 July 2015 - 22:41
    Description de l'image Warhammer FB logo.png. Rien a voir avec l'informatique, mais l'actualité me pousse à traiter de ce sujet. Pour ceux qui ne connaîtraient pas, Warhammer est une jeu de stratégie avec figurines édité par la société Games Workshop. La première édition date de 1983, j'ai découvert ce jeu en dans sa première édition en français en 1992. Depuis toutes ces années, les règles, les figurines et le background (on appelle ça le fluff maintenant), c’était régulièrement étoffés. Celui-ci à même donné lieu à un jeu de rôle auquel j'ai aussi beaucoup joué à une époque.

    Et je découvre que ce que je croyais etre la 9ème édition de ce jeu, annonce en réalité la fin de ce jeu.

    Au revoir Warhammer Fantasy Battle! Place à Warhammer Age of Sigmar.

    Nouvelles règles, nouvelle collection de figurines, background réécrit (le monde a été detruit...)

    Le nouveau jeu semble être taillé pour les escarmouche et tout laisse à penser que les anciennes figurines et les socles carrés vont peut à peu disparaître. Bref c'est vraiment un nouveau jeu.

    Je ne ferais pas plus de commentaire sur la destruction d'un monde que j'ai parcouru lors de nombreuses parties de jeu de rôle ou sur le design de discutables Sigmarines Stormcast Eternals pour essayer de positiver:

    • Ca y est, je jeu Warhammer Fantasy Battle est figé et sera libéré du poids du marketing. Après tout on ne demande pas aux Monopoly ou aux échecs d'avoir des règles mises à jour régulièrement, nous imposant, pour trouver des adversaires, d'acheter un nouveau livre de règle et des livres d'armées régulièrement.
    • Le marché des figurines d'occasion va peut-être baisser!
    • Jouer avec des vieilles règles va devenir la norme. Je n'ai jamais aimé la 8ème version avec les charges aléatoires. Ci-joint un site qui références les différentes éditions: http://dreadaxe.pagesperso-orange.fr/warhammer_editions.htm et un autre d'un inconditionnel de la 5ème édition http://patrice-m.eklablog.com/les-regles-v5-c19160377
    • Le jeu avec règles alternatives améliorées va peut-être aussi se développer. Par exemple les règles de Blackhammer, basées sur la version 7 de Warhammer avec un équilibrage des livres d'armées http://associationbrumes.forums-actifs.com/f23-blackhammer
    • Puisque Warhammer Fantasy Battle n'est plus supporté par Games Workshop, peut-être que d'avantage de joueur vont enfin accepter que nous complétions nos armées avec des figurines de marques alternatives. Par exemple celles-ci http://www.manticgames.com/
    • Les rôlistes vont reprendre la main sur le background pour faire vivre le Vieux Monde abandonné par Games Workshop: http://verrahrubicon.free.fr/
  • Tuesday 07 July 2015 - 08:23
    Après la sortie des recommandations Google Material Design sous forme de guidelines, Google propose enfin un toolkit concret permettant de mettre en place facilement ces best practices sur votre site.
  • Monday 06 July 2015 - 08:08
    Spectacle est un nouvel outil permettant de créer des slides et présentations modernes, basé sur React.js
  • Sunday 28 June 2015 - 23:21

    Prestashop permet dans sa version actuelle (1.6) de surcharger à peu prés .. tout !
    Ce qui est vraiment pratique pour modeler votre site e-commerce comme vous l'entendez sans toucher au cœur du code. Ce qui vous permettra ( dans une certaine mesure ) de pouvoir mettre à jour prestashop sans devoir réécrire vos fonctionnalités spécifiques ou votre thème.

    Mais il y a les modules

    Une autre des force de cet outil e-commerce, ce son ses modules, très nombreux qui permettent d'ajouter des fonctionnalités de façon .. "plug and play", activer désactiver etc .. super !!

    Seulement dans la documentation, impossible de trouver le moyen de surcharger un module existant.( je parle de la surcharge de la fonctionnalité apportée par ce module, les templates associés sont surchargeable de façon classique )
    jusqu'à maintenant, si vous souhaitiez changer le fonctionnement d'un module, vous aviez le choix entre :

    1. Toucher directement au code du module ( prochaine mise à jour .. et hop ... vous devez recommencer )
    2. Copier le module pour le dupliquer à votre sauce ( Assez lourd )

    La signature à utiliser

    Et bien figurez vous que c'est possible .. si si ..

    Note : uniquement à partir de la v1.6.0.11 ( merci à ChDUP pour cette précision )
    Pour surcharger une classe, vous utilisez l'écriture suivante :

    class [className sans Core] extends [className]Core
    

    dans le répertoire override/ ou modules/monModule/override/

    Et bien pour surcharger le code d'un module, il vous faut utiliser l'écriture suivante

    class [classNameModule]Override extends ClassNameModule
    

    Il suffit donc d'utiliser la chaine "Override" dans le nom de votre classe qui va surcharger le module souhaité .
    Par contre, il faut placer votre code dans le répertoire

    override/modules/moduleName/

    L'exemple qui va bien

    Prenons le cas du module BlockPaymentLogo disponible par défaut, qui permet d'afficher les logis de paiement sur une colonne de votre home.
    Moi je souhaite les afficher .. dans le pied de page "Footer", ce module n'a pas prévu ce cas, est n'est donc pas enregistré au bon Hook ( displayFooter ) . Bref impossible de le faire en natif .

    Surchargeons

    Nous allons commencer par créer le répertoire du même nom que celui d'origine

    override/modules/blockpaymentlogo/
    

    Puis créer le code de surcharge que voici.

    if (!defined('_PS_VERSION_'))
        exit;
    
    class BlockPaymentLogoOverride extends BlockPaymentLogo
    {
    
    
        public function install(){
    
            if( parent::install() ){
                return $this->registerHook('displayFooter');
            }else{
                return false;
            }
    
        }
    
        public function hookDisplayFooter($params)
        {
            return $this->hookLeftColumn($params);
        }
    
    }
    

    Petites explications,

    • on commence par déclarer notre classe comme il se doit ( en ajoutant Override, et en héritant de la classe du module d'origine )
    • Puis j'ajoute dans le constructeur l'association du module dans le hook displayFooter
    • Et enfin, je définis le code spécifique à ce hook ( ici le code sera le même que sur le hook leftcolumn, donc je ne réécris pas le code j'appelle celui du hook leftcolumn )

    Ne reste plus qu'à réinitialiser le module .. et voilà les logos qui apparaissent dans mon footer .

    Restez informé

    inscrivez vous à la newsletter pour recevoir les nouveaux billets par mail. ( formulaire en haut à droite )

  • Sunday 28 June 2015 - 11:33

    Un nouveau billet pense bête ...

    A l'installation de Mysql selon la version ou la façon de l'installer, les Time Zone nommées ne sont pas toujours ajoutées dans la base de données mysql. Voilà la petite ligne de commande à exécuter (sous linux) pour y remédier ( les ajouter )

    mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u <utilisateur admin> mysql
    

    Et voilà .. vous pouvez utiliser les requête

    SET time_zone = timezonename;
    

    Restez informé

    inscrivez vous à la newsletter pour recevoir les nouveaux billets par mail. ( formulaire en haut à droite )

  • Sunday 28 June 2015 - 11:33

    logo.png Un petit truc tout bête bien pratique, à tel point que je ne comprends pas pourquoi ce n'est pas en place dans les fonctionnalités de base de prestashop.

    Le besoin

    Prestashop 1.6

    Lorsqu'un employé crée un compte utilisateur depuis le backoffice de prestashop, aucun mail n'est envoyé au client final ( le mail de bienvenue contenant ses identifiants pour se connecter ), de plus l'employé doit entrer lui-même un mot de passe, ce qui n'est pas des plus pratique, surtout lorsque l'employé est en manque d'imagination, on peut se retrouver alors dans une problématique de sécurité non négligeable.

    La solution

    Nous allons simplement permettre à l'employé de laisser le champs "passwd" vide, il sera alors automatiquement généré de façon aléatoire.
    Enfin, nous allons ajouter un bouton "On/Off" dans le formulaire de création de compte qui va permettre à l'employé de décider si oui ou non les identifiants seront envoyés au client.

    Le code

    Bien commençons par créer la classe de surcharge

    override/controllers/admin/AdminCustomersController.php
    

    Nous allons donc surcharger les méthodes suivantes :

    1. processAdd()
    2. renderForm()

    Et créer une fonction

    1. sendConfirmationMail()

    Voici donc le code complet de notre fichier AdminCustomersController.php

    <?php
    /*
    *  05-2015
    *
    *  @author Christophe De Saint Leger 
    *  @Description Surcharge Formulaire création compte depuis le BackEnd
    */
    class AdminCustomersController extends AdminCustomersControllerCore
    {
    
    
            public function processAdd()
            {
                if (Tools::getValue('submitFormAjax'))
                    $this->redirect_after = false;
                // Check that the new email is not already in use
                $customer_email = strval(Tools::getValue('email'));
                $customer = new Customer();
                if (Validate::isEmail($customer_email))
                    $customer->getByEmail($customer_email);
                if ($customer->id)
                {
                    $this->errors[] = Tools::displayError('An account already exists for this email address:').' '.$customer_email;
                    $this->display = 'edit';
                    return $customer;
                }
                elseif (trim(Tools::getValue('passwd')) == '')
                {
                    $_POST['passwd'] = Tools::passwdGen();
                }
                if ($customer = parent::processAdd())
                {
                    $this->context->smarty->assign('new_customer', $customer);
                    if( Tools::getValue('sendWelcomeEmail') ){
                        $this->sendConfirmationMail($customer);
                    }
                    return $customer;
                }
                return false;
            }
    
    
    
    
            public function renderForm()
            {
    
                if (!($obj = $this->loadObject(true)))
                    return;
                
                $genders = Gender::getGenders();
                $list_genders = array();
                foreach ($genders as $key => $gender)
                {
                    $list_genders[$key]['id'] = 'gender_'.$gender->id;
                    $list_genders[$key]['value'] = $gender->id;
                    $list_genders[$key]['label'] = $gender->name;
                }
    
                $years = Tools::dateYears();
                $months = Tools::dateMonths();
                $days = Tools::dateDays();
    
                $groups = Group::getGroups($this->default_form_language, true);
                $this->fields_form = array(
                    'legend' => array(
                        'title' => $this->l('Customer'),
                        'icon' => 'icon-user'
                    ),
                    'input' => array(
                        array(
                            'type' => 'radio',
                            'label' => $this->l('Social title'),
                            'name' => 'id_gender',
                            'required' => false,
                            'class' => 't',
                            'values' => $list_genders
                        ),
                        array(
                            'type' => 'text',
                            'label' => $this->l('First name'),
                            'name' => 'firstname',
                            'required' => true,
                            'col' => '4',
                            'hint' => $this->l('Invalid characters:').' 0-9!&lt;&gt;,;?=+()@#"°{}_$%:'
                        ),
                        array(
                            'type' => 'text',
                            'label' => $this->l('Last name'),
                            'name' => 'lastname',
                            'required' => true,
                            'col' => '4',
                            'hint' => $this->l('Invalid characters:').' 0-9!&lt;&gt;,;?=+()@#"°{}_$%:'
                        ),
                        array(
                            'type' => 'text',
                            'prefix' => '<i class="icon-envelope-o"></i>',
                            'label' => $this->l('Email address'),
                            'name' => 'email',
                            'col' => '4',
                            'required' => true,
                            'autocomplete' => false
                        ),
                        array(
                            'type' => 'password',
                            'label' => $this->l('Password'),
                            'name' => 'passwd',
                            'required' => ($obj->id ? false : true),
                            'col' => '4',
                            'hint' => ($obj->id ? $this->l('Leave this field blank if there\'s no change.') :
                                sprintf($this->l('Password should be at least %s characters long. or void for automatic generation'), Validate::PASSWORD_LENGTH))
                        ), 
                        array(
                            'type' => 'switch',
                            'label' => $this->l('Send Welcome Email'),
                            'name' => 'sendWelcomeEmail',
                            'required' => false,
                            'class' => 't',
                            'is_bool' => true,
                            'values' => array(
                                array(
                                    'id' => 'sendWelcomeEmail_on',
                                    'value' => 1,
                                    'label' => $this->l('Enabled')
                                ),
                                array(
                                    'id' => 'sendWelcomeEmail_off',
                                    'value' => 0,
                                    'label' => $this->l('Disabled')
                                )
                            ),
                            'hint' => $this->l('Send the credentials to the client')
                        ),
                        array(
                            'type' => 'birthday',
                            'label' => $this->l('Birthday'),
                            'name' => 'birthday',
                            'options' => array(
                                'days' => $days,
                                'months' => $months,
                                'years' => $years
                            )
                        ),
                        array(
                            'type' => 'switch',
                            'label' => $this->l('Enabled'),
                            'name' => 'active',
                            'required' => false,
                            'class' => 't',
                            'is_bool' => true,
                            'values' => array(
                                array(
                                    'id' => 'active_on',
                                    'value' => 1,
                                    'label' => $this->l('Enabled')
                                ),
                                array(
                                    'id' => 'active_off',
                                    'value' => 0,
                                    'label' => $this->l('Disabled')
                                )
                            ),
                            'hint' => $this->l('Enable or disable customer login.')
                        ),
                        array(
                            'type' => 'switch',
                            'label' => $this->l('Newsletter'),
                            'name' => 'newsletter',
                            'required' => false,
                            'class' => 't',
                            'is_bool' => true,
                            'values' => array(
                                array(
                                    'id' => 'newsletter_on',
                                    'value' => 1,
                                    'label' => $this->l('Enabled')
                                ),
                                array(
                                    'id' => 'newsletter_off',
                                    'value' => 0,
                                    'label' => $this->l('Disabled')
                                )
                            ),
                            'disabled' =>  (bool)!Configuration::get('PS_CUSTOMER_NWSL'),
                            'hint' => $this->l('This customer will receive your newsletter via email.')
                        ),
                        array(
                            'type' => 'switch',
                            'label' => $this->l('Opt-in'),
                            'name' => 'optin',
                            'required' => false,
                            'class' => 't',
                            'is_bool' => true,
                            'values' => array(
                                array(
                                    'id' => 'optin_on',
                                    'value' => 1,
                                    'label' => $this->l('Enabled')
                                ),
                                array(
                                    'id' => 'optin_off',
                                    'value' => 0,
                                    'label' => $this->l('Disabled')
                                )
                            ),
                            'disabled' =>  (bool)!Configuration::get('PS_CUSTOMER_OPTIN'),
                            'hint' => $this->l('This customer will receive your ads via email.')
                        ),
                    )
                );
                
                // if we add a customer via fancybox (ajax), it's a customer and he doesn't need to be added to the visitor and guest groups
                if (Tools::isSubmit('addcustomer') && Tools::isSubmit('submitFormAjax'))
                {
                    $visitor_group = Configuration::get('PS_UNIDENTIFIED_GROUP');
                    $guest_group = Configuration::get('PS_GUEST_GROUP');
                    foreach ($groups as $key => $g)
                        if (in_array($g['id_group'], array($visitor_group, $guest_group)))
                            unset($groups[$key]);
                }
    
                $this->fields_form['input'] = array_merge(
                    $this->fields_form['input'],
                    array(
                        array(
                            'type' => 'group',
                            'label' => $this->l('Group access'),
                            'name' => 'groupBox',
                            'values' => $groups,
                            'required' => true,
                            'col' => '6',
                            'hint' => $this->l('Select all the groups that you would like to apply to this customer.')
                        ),
                        array(
                            'type' => 'select',
                            'label' => $this->l('Default customer group'),
                            'name' => 'id_default_group',
                            'options' => array(
                                'query' => $groups,
                                'id' => 'id_group',
                                'name' => 'name'
                            ),
                            'col' => '4',
                            'hint' => array(
                                $this->l('This group will be the user\'s default group.'),
                                $this->l('Only the discount for the selected group will be applied to this customer.')
                            )
                        )
                    )
                );
    
                // if customer is a guest customer, password hasn't to be there
                if ($obj->id && ($obj->is_guest && $obj->id_default_group == Configuration::get('PS_GUEST_GROUP')))
                {
                    foreach ($this->fields_form['input'] as $k => $field)
                        if ($field['type'] == 'password')
                            array_splice($this->fields_form['input'], $k, 1);
                }
    
                if (Configuration::get('PS_B2B_ENABLE'))
                {
                    $risks = Risk::getRisks();
    
                    $list_risks = array();
                    foreach ($risks as $key => $risk)
                    {
                        $list_risks[$key]['id_risk'] = (int)$risk->id;
                        $list_risks[$key]['name'] = $risk->name;
                    }
    
                    $this->fields_form['input'][] = array(
                        'type' => 'text',
                        'label' => $this->l('Company'),
                        'name' => 'company'
                    );
                    $this->fields_form['input'][] = array(
                        'type' => 'text',
                        'label' => $this->l('SIRET'),
                        'name' => 'siret'
                    );
                    $this->fields_form['input'][] = array(
                        'type' => 'text',
                        'label' => $this->l('APE'),
                        'name' => 'ape'
                    );
                    $this->fields_form['input'][] = array(
                        'type' => 'text',
                        'label' => $this->l('Website'),
                        'name' => 'website'
                    );
                    $this->fields_form['input'][] = array(
                        'type' => 'text',
                        'label' => $this->l('Allowed outstanding amount'),
                        'name' => 'outstanding_allow_amount',
                        'hint' => $this->l('Valid characters:').' 0-9',
                        'suffix' => $this->context->currency->sign
                    );
                    $this->fields_form['input'][] = array(
                        'type' => 'text',
                        'label' => $this->l('Maximum number of payment days'),
                        'name' => 'max_payment_days',
                        'hint' => $this->l('Valid characters:').' 0-9'
                    );
                    $this->fields_form['input'][] = array(
                        'type' => 'select',
                        'label' => $this->l('Risk rating'),
                        'name' => 'id_risk',
                        'required' => false,
                        'class' => 't',
                        'options' => array(
                            'query' => $list_risks,
                            'id' => 'id_risk',
                            'name' => 'name'
                        ),
                    );
                }
    
                $this->fields_form['submit'] = array(
                    'title' => $this->l('Save'),
                );
    
                $birthday = explode('-', $this->getFieldValue($obj, 'birthday'));
    
                $this->fields_value = array(
                    'years' => $this->getFieldValue($obj, 'birthday') ? $birthday[0] : 0,
                    'months' => $this->getFieldValue($obj, 'birthday') ? $birthday[1] : 0,
                    'days' => $this->getFieldValue($obj, 'birthday') ? $birthday[2] : 0,
                );
    
                // Added values of object Group
                if (!Validate::isUnsignedId($obj->id))
                    $customer_groups = array();
                else
                    $customer_groups = $obj->getGroups();
                $customer_groups_ids = array();
                if (is_array($customer_groups))
                    foreach ($customer_groups as $customer_group)
                        $customer_groups_ids[] = $customer_group;
    
                // if empty $carrier_groups_ids : object creation : we set the default groups
                if (empty($customer_groups_ids))
                {
                    $preselected = array(Configuration::get('PS_UNIDENTIFIED_GROUP'), Configuration::get('PS_GUEST_GROUP'), Configuration::get('PS_CUSTOMER_GROUP'));
                    $customer_groups_ids = array_merge($customer_groups_ids, $preselected);
                }
    
                foreach ($groups as $group)
                    $this->fields_value['groupBox_'.$group['id_group']] =
                        Tools::getValue('groupBox_'.$group['id_group'], in_array($group['id_group'], $customer_groups_ids));
    
                return AdminController::renderForm();
            }
    
    
    
            /**
             * sendConfirmationMail
             * @param Customer $customer
             * @return bool
             */
            protected function sendConfirmationMail(Customer $customer)
            {
                if (!Configuration::get('PS_CUSTOMER_CREATION_EMAIL'))
                    return true;
    
                return Mail::Send(
                    $this->context->language->id,
                    'account',
                    Mail::l('Welcome!'),
                    array(
                        '{firstname}' => $customer->firstname,
                        '{lastname}' => $customer->lastname,
                        '{email}' => $customer->email,
                        '{passwd}' => Tools::getValue('passwd')),
                    $customer->email,
                    $customer->firstname.' '.$customer->lastname
                );
            }
    
    
    
    }
    

    Attention à ne pas oublier

    Pour toute nouvelle surcharge, il vous faut supprimer le fichier de cache suivant

    cache/class_index.php
    

    Résultat

    Et voilà le résultat au niveau du formulaire

    Capture_d_e_cran_2015-05-16_a__14.27.06.png

    Bonne journée,

    Ch.

    Restez informé

    inscrivez vous à la newsletter pour recevoir les nouveaux billets par mail. ( formulaire en haut à droite )

  • Sunday 28 June 2015 - 11:33

    J'ai eu quelques soucis récemment avec une instance Amazon qui héberge une base de données Mysql très sollicitée par période.
    En effet les données de la base étaient sur la même partition que le système ( déjà c'est mauvais ), celle-ci étant fortement sollicitée en IO, la charge système se met à grimper, les temps d'attente d’accès au disque étant de plus en plus grand, jusqu'au crash complet .

    La solution simple et rapide est de déplacer les données vers une partition dédiée, avec des performances en IO plus importantes (tant qu'à faire). C'est dans ce contexte que je vais présenter, dans ce billet, la mise en place d'une partition en Raid0 pour augmenter significativement les IO/s et surtout éviter de surcharger le système.

    Ce que l'on va voir

    • Création de système de fichiers XFS
    • Création d'un Raid logiciel
    • Monitoring avec atop
    • Ajout d'un disque au Raid
    • Extension d'une partition XFS

    Etat des lieux

    Je vais utiliser une instance micro ( gratuite ) sous Debian Jessie en HVM ( virtualisation totale ). je vais y attacher 4 disques.

    Capture_d_e_cran_2015-05-17_a__10.28.54.png

    • /dev/xvda pour le système
    • /dev/sdb pour tester les perfs. sur un seul disque
    • /dev/sdc premier disque du Raid
    • /dev/sdb deuxième disque du Raid

    Installation des outils

    Le système étant vierge nous allons installer les paquets nécessaires pour les manipulations ci-dessous.

    sudo apt-get install xfsprogs atop mdadm
    

    Premier test : Disque seul

    Pour pouvoir comparer, nous allons commencer avec un test sur un disque "seul" possédant une partition XFS

    Voici comment sont perçus les disques à ce moment

    Capture_d_e_cran_2015-05-17_a__10.35.40.png

    Commençons par créer la partition :

    sudo cfdisk /dev/xvdb
    

    Une fois la partition créée, voici comment sont perçus les disques

    Capture_d_e_cran_2015-05-17_a__10.37.39.png

    Nous allons maintenant créer le système de fichiers sur cette nouvelle partition

    mkfs.xfs /dev/xvdb1
    

    Enfin il ne nous reste plus qu'à monter cette partition sur un répertoire que nous allons également créer maintenant

    mkdir /home/admin/diskLocal
    mount -t xfs /dev/xvdb1 /home/admin/diskLocal/
    

    Dirigeons nous dans ce répertoire et effectuons le premier test basique, grâce à l'outil dd

    cd /home/admin/diskLocal
    dd if=/dev/zero of=bench.dat bs=1M count=1024 oflag=direct
    

    Pendant le test on voit bien grâce à la commande atop, l'utilisation du disque qui est à son maximum

    Capture_d_e_cran_2015-05-17_a__10.45.21.png

    Et voici le résultat

    Capture_d_e_cran_2015-05-17_a__10.45.39.png

    Deuxième test : 2 Disques en Raid0

    Commençons par construire notre raid0 "software" ( via la commande mdadm )

    mdadm --create --verbose /dev/md0 --level=stripe --raid-devices=2 /dev/xvdc /dev/xvdd
    

    Ce qui nous donne :

    Capture_d_e_cran_2015-05-17_a__10.48.43.png

    Un petit check :

    mdadm -D /dev/md0
    

    Maintenant, créons notre système de fichiers sur md0

    mkfs.xfs /dev/md0
    

    Enfin il ne nous reste plus qu'à monter cette partition sur un répertoire que nous allons créer: diskRaid

    mkdir /home/admin/diskRaid
    mount -t xfs /dev/md0 /home/admin/diskRaid/
    

    Dirigeons nous dans ce répertoire et effectuons le second test sur ce disque Raid0

    cd /home/admin/diskRaid
    dd if=/dev/zero of=bench.dat bs=1M count=1024 oflag=direct
    

    Regardons ce qui se passe pendant le test

    Capture_d_e_cran_2015-05-17_a__10.52.27.png

    Les deux disques sont en pleine charge, et quelques secondes plus tard ...

    Capture_d_e_cran_2015-05-17_a__10.52.37.png

    On passe donc de 30 secondes à 18 sec. pour effectuer ce test et un débit d’écriture de 35.5MB/s à 51MB/s

    Conclusion

    Il est plus intéressant de mettre en place 2 disques en Raid0 qu'avoir un gros disque pour améliorer les IO/s.

    Ajoutons un disque au Raid0

    Si nous ajoutons un disque à notre Raid0, nous passerons ainsi à 3 disques

    Voici le disque à ajouter

    • /dev/xvde

    Capture_d_e_cran_2015-05-17_a__14.21.34.png

    Ajoutons le à notre raid md0

    sudo mdadm --grow /dev/md0 --raid-devices=3 --level=0 --add /dev/xvde
    sudo xfs_growfs /dev/md0
    

    Regardons si tout est ok

    lsblk
    

    Capture_d_e_cran_2015-05-17_a__14.59.08.png

    Vérifions que la partition fasse bien 15G

    df -h
    

    Capture_d_e_cran_2015-05-17_a__15.00.30.png

    Bien ça me semble parfait, lançons le troisième test

    cd /home/admin/diskRaid
    dd if=/dev/zero of=bench.dat bs=1M count=1024 oflag=direct
    

    Capture_d_e_cran_2015-05-17_a__15.02.34.png

    Résultat :

    Capture_d_e_cran_2015-05-17_a__15.03.51.png

    Les performances restent les mêmes, certainement limitées par la virtualisation ou simplement physiquement, cependant la charge étant répartie sur 4 disques, l'occupation ne dépasse pas les 65%, ce qui permet d'avoir d'autres processus en parallèles.

    L'ajout de disques reste donc très intéressante pour pouvoir encaisser une forte charge d'IO/s .

    Bon tests ,

    Ch.

    Restez informé

    inscrivez vous à la newsletter pour recevoir les nouveaux billets par mail. ( formulaire en haut à droite )

  • Sunday 28 June 2015 - 11:32

    Ce billet va présenter deux outils Amazon autour d'un exemple concret, la gestion des Bounces en utilisant Amazon en relais pour vos mails.

    Bounces

    Lorsque vous envoyez une "newsletter" à de nombreuses adresses mails, il y a ce que l'on appel les "BOUNCES" , qui traduit donne "rebonds". Il s'agit en fait du retour des mails qui partent vers une adresse qui ne fonctionne pas. Il y a plusieurs raisons qui peuvent engendrer un tel rebond, certaines raisons sont temporaires, d'autres définitives. Par exemple :

    • Le destinataire n’existe pas ( définitif )
    • Boite pleine ( temporaire )
    • Erreur Serveur ( temporaire )
    • Plainte ( définitif )
    • Pas de réponse ( temporaire )
    • Pas de résolution DNS ( définitif )

    Pourquoi traiter ces rebonds ?

    Tout est une histoire de réputation, en effet ne pas traiter ces rebonds et les laisser s'augmenter à chaque newsletter, peut tout doucement vous faire passer pour un "spammeur", d'autant que nous utilisons le relais mails Amazon ( service SES ) qui va réduire votre capacité à envoyer des mails si le nombre de bounces augmente sans action de votre part.

    Deuxième raison, financière, pourquoi continuer à envoyer et payer des mails à des adresses qui n’existent pas ! ( ok le cout du mail est ridicule avec Amazon, mais c'est une question de principe )

    Comment les gérer ?

    Souvent, vous définissez une adresse de retour via ue entête spécifique, dédiée au retour "système" ( Entête : return-path ), ainsi les bounces atterrissement dans cette boite mail dédiée et c'est à vous de les traiter. ( les outils des mailing intègrent souvent une fonction de récupération des bounces par une lecture de boite mail en pop ).

    Cependant, Amazon permet d'aller un peu plus loin grâce à son service de notification SNS.
    Le principe est simple, lorsque Amazon reçoit un "Bounce" il va transmettre un message de notification dans le topic associé . A ce "topic" nous allons lui associer une "inscription" ( qui est en fait une action à lancer lorsque qu'un "message" arrive sur ce topic ). Dans notre cas, ce sera une simple requête HTTP avec dans son corps les informations du Bounce en format JSON.

    Création du Topic

    Depuis l'interface Amazon SNS, vous créez un nouveau "topic"

    Capture_d_e_cran_2015-05-24_a__11.04.03.png

    On va le nommer Bounces

    Capture_d_e_cran_2015-05-24_a__11.04.33.png

    Puis nous allons créer une "subscription"

    Capture_d_e_cran_2015-05-24_a__11.04.57.png

    On va donc choisir le protocole HTTP et dans le champ "endpoint", nous mettons l'url qui pointe sur notre script décrit plus bas ( exemple : http://lindev.fr/sns.php )

    Capture_d_e_cran_2015-05-24_a__11.05.20.png

    Pour le moment, voici notre script sns.php :

    <?php
    ob_start();
    var_dump( $_POST );
    $content = ob_get_clean();
    $fp = fopen('sns_validation.txt', a+);
    fwrite($fp,$content);
    fclose($fp);
    

    Le but étant d'enregistrer dans un fichier texte, ce que nous envoi Amazon . NÉCESSAIRE AU DÉBUT POUR LA VALIDATION DE LE SOUSCRIPTION

    Vous pouvez maintenant valider votre formulaire d'ajout de "subscription", vous allez alors voir apparaitre dans le fichier sns_validation.txt une url pour valider définitivement l'enregistrement.
    Il vous suffit alors d'ouvrir cette url pour terminer l'enregistrement.

    SES et SNS, le lien

    Maintenant nous allons faire en sorte que tout les bounces liés à un domaine géré par le service SES d'amazon, utilisent le système de notification SNS et surtout le "topic" fraichement créé.

    Pour cela, nous allons dans la section SES d'amazon, ( le domaine doit auparavant être validé pour pouvoir relayer des mails, pour cela il suffit d'ajouter des champs TXT dans la zone DNS. La documentation d'amazon est très bien faite à ce sujet ).

    Nous allons donc dans la section Notifications, et l'on édite la configuration

    Capture_d_e_cran_2015-05-24_a__11.06.36.png

    Et là nous allons choisir les options adéquats

    Capture_d_e_cran_2015-05-24_a__11.06.52.png

    On sélectionne donc notre souscription dans les menus "Bounces" et "Complaints" uniquement, car ce sont ces deux cas que nous souhaitons traiter automatiquement.

    Et voilà, après validation, dés qu'un "bounce" montre le bout de son nez, un message est transmit au service SNS et une requête HTTP avec toutes les informations nécessaires dans un format JSON est lancée en POST.

    Tests

    Pour tester le service, Amazon nous met à disposition des adresses spécifiques, qui simulent chaque cas.

    • bounce@simulator.amazonses.com
    • complaint@simulator.amazonses.com

    Ne vous reste donc plus qu'à envoyer un mail à ces deux adresses, et regarder le contenu des données POST qui vont s'ajouter dans votre fichier sns_validation.txt

    Cas simple

    Imaginons, que nous souhaitons, simplement lister les mails des Bounces et Complaints dans un fichier TXT avec trois champs

    1. Date de réception du Bounce
    2. Adresse mail
    3. Type de Bounce ( temporaire ou définitif ou complaint ).

    Nous allons donc extraire ces données du JSON, notre script sns.php devient :

    <?php
    
    // Fetch the raw POST body containing the message
    $postBody = file_get_contents('php://input');
    
    // JSON decode the body to an array of message data
    $msg = json_decode($postBody, true);
    
    if ($msg) {
    
        //Ouverture du fichier de log
        $fp = fopen('sns_bounces.txt', 'a+');
    
        $data = json_decode($msg['Message'],true);
        $typeMsg = $data['notificationType'];//A utiliser pour séparer plaintes et Bounces
    
        switch( $typeMsg ){
            case 'Bounce':
                $bounceType = $data['bounce']['bounceType'];
                foreach( $data['mail']['destination'] AS &$mail ){
                    //Ecriture dans la liste txt
                    fwrite($fp, date('Y-m-d H:i:s').";".$mail.";". $bounceType . "\n");
                }
            break;
            case 'Complaint':
                foreach( $data['mail']['destination'] AS &$mail ){
                    //Ecriture dans la liste txt
                    fwrite($fp, date('Y-m-d H:i:s').";".$mail.";complaint" . "\n");
                }
            break;
        }
        fclose($fp);
    
    }
    

    Vous allez alors vous retrouver avec une liste exploitable comme un CSV .

    L'idée, c'est d'améliorer ce script de démo pour une désinscription automatique dans votre outil de mailing ( très simple avec phplist )

    Restez informé

    inscrivez vous à la newsletter pour recevoir les nouveaux billets par mail. ( formulaire en haut à droite )

  • Wednesday 24 June 2015 - 22:15
    Nokia LUMIAAujourd'hui, j'ai décidé de partager avec vous une offre de remboursement proposée par Microsoft sur le Nokia Lumia 1320, appareil 4G au format "Phablette" 6 pouces. Je précise que je n'ai aucun intérêt chez Microsoft, mais simplement que j'apprécie Windows Phone 8 et que je pense que cette offre de remboursement est intéressante. D'ailleurs je viens de commander cet appareil pour en bénéficier.
    L'offre de remboursement est de 100€ en cas d'achat dans une des boutiques participantes.
    Bien sûr, avec ce type d'offres il faut être hyper rigoureux pour que le dossier soit validé. Mais j'ai déjà bénéficié d'une telle offre sans souci lors de l'achat de mon Lumia 625.
    Cet appareil n'est pas tellement plus puissant que mon Lumia 625. Mais je vois là l'occasion de tester un appareil de très grand format pour un coût modéré car je ne suis pas vraiment certain de me faire un appareil de cette dimension.
    Le formulaire de l'offre est téléchargeable ici: http://www.microsoft.com/fr-fr/mobile/les-offres-promotionnelles-lumia/
    Il y a aussi des offres sur les Lumia 530 et 635 plus puissants, mais qui ne m'intéressent pas en raison de l'absence de flash sur ces appareils. Ce n'est pas que je prenne beaucoup de photo, mais je m'en sert régulièrement comme lampe de poche de secour.
  • Wednesday 24 June 2015 - 22:13
    On lit régulièrement des news, relayées sur tout les sites généralistes et indiquant les parts de marchés des différents systèmes d'exploitations pour mobiles. Les chiffres les plus souvent cités sont issus de deux cabinets d'études.

    Gartner (http://www.gartner.com/newsroom/archive/)
    et
    kantar (http://www.kantarworldpanel.com/fr/smartphone-os-market-share/)

    Pour ma part, j'ai voulu faire un historique des parts de marché. J'ai utilisé les chiffres de Gartner qui remontent jusqu'en 2009 et j'ai essayé de reconstituer des statistiques trimestrielles à partir de leurs communiqués de presse. Ces chiffres concernent le nombre d'appareils vendu chaque trimestre, et pas le nombre d'appareils en cours d'utilisation.

    J'ai trouvé assez amusant de pouvoir revivre les grand événements du marché des smartphones à travers ces chiffres:
    Le déclin de Nokia entraînant Symbian dans son sillage, la naissance et mort de Bada, la constante mais anecdotique présence de Microsoft, la lente agonie de RIM, le pic à la sortie de chaque génération d'iPhone et l'arrivée de l’écrasant rouleau compresseur Google.
  • Tuesday 23 June 2015 - 09:09
    Asciinema est un script Go et service en ligne permettant d'enregistrer et partager vos sessions de terminal / console sous forme de vidéo.
  • Friday 19 June 2015 - 13:34
    Au début de ce blog, j'avais en particulier posté des messages concernant l'alimentation et la consommation électrique des Raspberry Pi. Voici qu'un petit incident sur mon Raspberry Pi de test me rappelle qu'il ne faut pas faire n'importe quoi avec l'électricité.
    Le site officiel annonce que les besoins du Raspberry Pi sont entre 700-1000mA. Il y est conseillé d'utiliser une alimentation de 1200mA issu d'un fabricant reconnu.
    J'ai alimenté pendant 2 semaines non stop mon Raspberry Pi de test avec une alimentation générique sans marque de 500mA. Le système est resté stable pendant la durée mais elle a fini par griller.

    Je n'ai heureusement pas eu d'autres dégâts (de l'extérieur l'alimentation semblait intacte) et le Raspberry Pi fonctionne toujours.
    L'alimentation Bluestork que j'avais choisi en mai 2013 n'a quand à elle toujours pas lâché. L'alimentation Apple fonctionne elle aussi toujours (mais je m'en suis moins servi)
  • Monday 15 June 2015 - 22:55
    Windows InsiderJe teste Windows 10 sur PC depuis quelques temps déjà, mais je n'avait pas d'appareil disponible pour tester la version pour téléphone. Venant de changer mon Lumia 625 pour un Lumia 1320, je n'ai pas pu résister à l'envie de le tester sur le Lumia 625.

    Comment faire pour le tester:

     
     
     
    • Exécuter l'application "Windows Insider". Deux modes de fonctionnement sont proposés sur cette application : Slow = version plus ou moins stable ou Fast = dernière version avec plus de bugs. Pour mon Lumia 625 seule l'option Fast proposait de mises à jour
     
    • Passer ensuite dans le menu de mise à jour "Paramètres/Mise à jour du téléphone/vérifier la disponibilité des mises à jour"
     
    • Installer la mise à jour
     
    • Le téléphone redémarre pendant une éternité en installant la mise à jour.
    Notez bien qu'il s'agit d'une mise à jour et pas d'une réinstallation complète. Les paramètres et programmes devraient normalement être préservés. Malheureusement, dans mon cas, le menu principal était totalement instable. J'ai pu le rendre utilisable en le réinitialisant depuis le menu "Paramètres/Système/A propos de/réinitialiser votre téléphone". Il s'est alors réinstallé avec un système propre tout en restant en Windows 10.
     
    Honnêtement, ce système ne bouleverse pas grand chose par rapport à Windows 8.1. Les changements les plus remarquables sont dans les menus de paramètres qui son bien plus ordonnés et  compréhensible que les anciens.





  • Monday 15 June 2015 - 22:54
    J'en ai déjà parlé sur ce blog, mon passage d'Android à Windows Phone 8.1 m'a permis d'apprécier à sa juste valeur le travail de Microsoft sur Windows 8.1. L'interface en tuile, qui m'avait semblé ridicule au départ, est devenue pertinente après un passage par le tactile.

    C'est pourquoi je suis avec intérêt des évolutions proposées par Microsoft dans le système Windows 10. Je suis en particulier enthousiasmé par l'interface graphique à mi-chemin entre celle de Windows 7 et celle de Windows 8, le nouveau navigateur Edge (anciennement Project Spartan) et les applications universelles (Windows Universal Apps) compatibles sur smartphone comme sur PC.

    La version définitive devrait être gratuite en mise à jour depuis Windows 7 et Windows 8 à partir de  la fin du mois de juillet, mais ce n'est pas parce que c'est gratuit qu'il ne faut pas essayer avant d'acheter!

    Pour télécharger l'ISO du dvd d'installation de la dernière version Technical Preview ca se passe ici:


    Il  a encore des bugs, donc installez la plutôt sur une machine de test ou une machine virtuelle. Je l'ai utilisé sur un vieux PC en core2duo, et ca reste plutôt réactif.
  • Wednesday 10 June 2015 - 10:34
    Bonjour,

    Ma théière et moi nous sommes  trouvés éloignées du Web pendant plusieurs longues semaines pour raisons personnelles. Je suis totalement débordé et aurait du mal à rédiger des articles prochainement, mais j'ai quand même réussi à trouver un peu de temps pour rebrancher la théière.

    A bientôt.
  • Tuesday 09 June 2015 - 18:41
    Dimanche dernier, j'ai eu le plaisir de participer à un atelier d'initiation Arduino à l'ACoLab (Atelier Collaboratif) de Clermont-Ferrand. Le but de cet atelier était d'initier les participants à l'utilisation de l'Arduino sous forme de premier contact avec l'appareil, l'installation de l'IDE Arduino, la découverte du langage utilisé par l'Arduino, la compréhension des composants électroniques employés (LED, résistance, bouton poussoir, etc...) et la réalisation de circuits. Continuer la lecture
  • Tuesday 02 June 2015 - 07:30
    Passpie est un outil développé en Python permettant de gérer vos mots de passe directement depuis votre terminal.
  • Monday 01 June 2015 - 10:56

    Offurl.fr propose aux internautes les liens de téléchargement des logiciels directement sur les sites des éditeurs pour limiter les risques d'infecter leurs PC de malwares.

    Offurl est un moteur de recherche spécialisé qui permet de télécharger les logiciels directement sur les sites officiels, c-à-d ceux des éditeurs. Cela a le double avantage d'éviter aux internautes d'installer des logiciels malveillants ou publicitaires et de disposer de la dernière version des programmes.


    Il suffit de lancer une recherche dans le champ de recherche et de cliquer sur "Rechercher" pour se voir proposer le site de l'éditeur.

    Le site est branché Web 2.0, puisque les internautes peuvent participer à l'échange d'informations. Et pour cause, la communauté peut contribuer au projet en y soumettant un logiciel non encore répertorié et l'URL de téléchargement. Ou bien en signalant les erreurs ou les liens morts. Après vérification, le programme soumis sera validé pour enrichir la base de données du service en ligne communautaire.

    Site : http://offurl.fr/

  • Tuesday 26 May 2015 - 07:35
    Toolbar.js est un plugin jQuery permettant de créer des toolbar contextuelles sous forme de tooltips.
  • Monday 18 May 2015 - 07:35
    Watermark.js est une bibliothèque Javascript ES6 permettant de générer des watermarks sur des images en Javascript.
  • Saturday 09 May 2015 - 22:05
  • Monday 04 May 2015 - 09:10
    Visual Studio Code est un IDE gratuit permettant de développer sur Windows, Linux et Mac OS X avec les langages web, Node.js et .NET.
  • Wednesday 29 April 2015 - 21:07
    On ne le dira jamais assez. Prenez un peu de recul avant de paniquer, sachez que les opérateurs ou les différents services (public, banque etc) ont déjà vos coordonnées et que la grande faiblesse de cette méthode réside dans l'URL qui ne peut qu'être bidon.

    C'est dit!
    (Permalink)
  • Sunday 26 April 2015 - 09:53
    Debian, la distribution GNU/Linux qui tient une place importante dans ma vie informatique quotidienne (et dans mon petit cœur) vient de passer un nouveau cap et change de nom pour l'occasion : Bienvenue à toi Jessie. Depuis bientôt 24 mois … Continuer la lecture
  • Friday 24 April 2015 - 20:11
    Un tuto sympa pour installer Arch Linux en full Disk encryption. Je garde ça sous le coude pour le jour où l'envie de bidouiller me reprend :)
    (Permalink)
  • Wednesday 22 April 2015 - 18:19
    Librairie javascript pour un jolie "back to top" (pensez à activer le son de votre ordi)
    (Permalink)
  • Tuesday 21 April 2015 - 10:14

    Le titre m’avais accroché, j’ai donc décidé de lire la suite. L’article très complet résume les dernières informations concernant la loi Anti-terroriste voté en ce moment au parlement Français.

    Voici l’extrait qui m’a fait bondir de ma chaise :

    Il faut savoir sacrifier quelque peu sa vie privée.

    Cette affirmation ne me conviens pas du tout.
    Je ne supporte pas l’idée que que l’on espionne ce que je dise/écrive sous prétexte de sécurité. On ne peux pas surveiller tous les internautes sans distinctions pour faire un tris à posteriori.

    Il faut au contraire des surveillances ciblées. Ne nous faisons pas d’illusions, les terroristes savent lire un tutoriel sur internet pour utiliser un VPN et TOR.

    Cette loi n’est là que pour faire plaisir à l’opinion publique.

    En réduisant nos libertés, le terroristes gagnent !

    je vous renvoi vers l’article d’origine :

    The post Surveillance de masse en France appeared first on Le blog de Luc.

  • Thursday 16 April 2015 - 18:36
    J'ai récemment voulu donner un peu de souffle à mon média center préféré en remplaçant mon bon vieux Raspberry Pi modèle B par un Raspberry Pi 2. Je suis franchement toujours aussi content de mon Raspbilight, il est plaisant à … Continuer la lecture
  • Tuesday 14 April 2015 - 08:26
    Windows PowerShell : Fonctionnalités avancées (index.php?option=com_content task=view id=418 Itemid=80) , s'adressait aux scripteurs ayant déjà acquis les bases de PowerShell,...
  • Monday 13 April 2015 - 08:05
    Grav est un CMS PHP open source en flat file, très simple à mettre en place, et ne nécessitant aucune base de données.
  • Thursday 09 April 2015 - 19:03
    Toujours utile et la galerie de lolcats à la fin vaut le coup.
    (Permalink)
  • Wednesday 08 April 2015 - 11:47

    Je sais bien que cela peut sembler un peu mesquin de sortir ce blog de son sommeil pour faire savoir qu’à la suite d’un licenciement économique, je suis à la recherche d’un travail sur Lyon et ses alentours, mais comme le dit l’adage populaire : aux grands maux, les grands remèdes.

    Donc, si d’aventure vous cherchez un développeur PHP agile avec 15 ans d’expérience, qui pratique le TDD, qui dispose de solides bases en architecture logiciel et en qualité logiciel, qui a envie de faire partager ses connaissances et qui aime relever des défis techniques, je suis votre homme !

  • Tuesday 07 April 2015 - 20:56
    Très bien fait et pour info, le gars c'est tapé les 5 saisons et a tout compté lui-même. Visez la tête :)
    (Permalink)
  • Tuesday 07 April 2015 - 02:00
    Mise à jour 07/04/2015  Shay Levy (https://mvp.support.microsoft.com/profile=EEDF79D9-9D71-4AC0-A225-4E8C09FF03A1), un talentissime MVP PowerShell et développeur, a publié un module PowerShell dont l'objetif est de...
  • Saturday 04 April 2015 - 15:39
    Modifier les raccourcis clavier en ligne de commandes.
  • Friday 03 April 2015 - 19:05
    Même si on n'est pas fan, c'est toujours sympa ce genre de stats et de petits détails.
    (Permalink)
  • Thursday 02 April 2015 - 18:41

    C’est parti Codeigniter 3.0 est maintenant disponible en version finale, la lise des changements étant longue comme mon bras, je vous invite à vous plonger dans le changelog officiel sur cette page.

    A partir de maintenant c’est un nouveau départ pour le framework qui j’espère sera amené à évoluer plus souvent. Je lui souhaite le meilleur mais je fait aussi quelques recommandations.

    Une nouvelle version à minima

    La version minimale est php 5.2.x, c’est une version qui n’est plus supportée par PHP depuis 4 ans (la doc dit qu’ils recommandent PHP 5.4.x). Là je suis un peux plus content mais aucun des apports de la version ne sont utilisé (TRAITS, namespaces…). Une refonte du cœur doit être entreprise pour tirer le meilleur parti de ces nouveaux ajouts.

    Et maintenant je fais quoi ?

    Et bien je vais tenter de migrer au moins un projet vers codeigniter 3.0 pour voir les limitations et les opportunités de la nouvelle version. Si tous se passe correctement, je migre mes autres projets.

     

    La nouvelle version est disponible ici

    See you soon !

    The post Codeigniter 3.0 is out ! appeared first on Le blog de Luc.