Weblogs Código

Bitácora de Javier Gutiérrez Chamorro (Guti)

La programación era cosa de mujeres

August 22, 2016 05:13 PM

Según datos recientes, el porcentaje de mujeres desempeñando tareas de programación en el ámbito informático, es del orden de 12%. Nada que nos sorprenda, a poco contacto que tengamos con la profesión, eminentemente masculina. Si bien es cierto que en tareas que combinan creatividad, como la maquetación web, la cifra puede ascender levemente. La curva […]

» Leer más, comentarios, etc...

Poesía Binaria

Cómo crear un plugin para WordPress. Making of SimTerm: pantalla de configuración (segunda parte)

August 22, 2016 08:44 AM

simterm
WordPress es un sistema gestor de contenidos muy utilizado mundialmente. Y uno de sus puntos fuertes es su capacidad para que cualquiera de nosotros lo pueda extender fácilmente. Aprovechando el mismo núcleo que proporciona WordPress con funciones y clases que nos permiten interactuar con la plataforma crearemos nuestras propias funcionalidades que harán de nuestra página o blog algo único.
Este post es la segunda parte, si prefieres empezar desde cero, te recomiendo visitar primero Cómo crear un plugin para WordPress. Making of SimTerm.

Esta vez nos centraremos en la configuración de nuestro plugin.

Configuración

Nuestro plugin necesitará algo de configuración por defecto para nuestros terminales, como serán el tema y la velocidad por defecto (iremos metiendo más opciones luego).

Para crear la configuración del plugin, vamos a utilizar la API de configuración de WordPress (WordPress Settings API) que está con nosotros desde hace algunos años y nos ayuda enormemente con este tema proporcionando sencillez a la hora de programarla y una capa de seguridad, con la que nos podemos olvidar de hacer muchas comprobaciones a los datos que nos llegan del usuario (no están de más, pero es un tostón hacerlo, y WordPress nos quita trabajo).

Para separar la configuración del propio plugin he creado el archivo simterm-settings.php que contendrá la clase SimTermSettings, será de tipo singleton y se encargará de presentar distintas vistas para la pantalla de configuración. Se ha creado una vista para cada tipo de campo, como detallaremos más adelante.

Antes de adentrarnos en la configuración, primero debemos añadir un par de acciones en la inicialización de nuestro plugin (aquella función init() de la primera parte), aunque lo importante es que esto se ejecute siempre, puede estar escrito directamente en el archivo PHP principal del plugin:

1
2
    add_action('admin_menu', array('Clase', 'register_settings_menu'));
    add_action('admin_init', array('Clase', 'settingsInit'));

Con estas dos funciones, lo primero es añadir un elemento de menú para nuestro plugin (al menos que la página de configuración aparezca), y con el segundo inicializamos la configuración del plugin (estableciendo qué cosas se van a configurar y cómo). En el ejemplo he puesto ‘Clase’, ya que el segundo parámetro de add_action() es un callback que llamará WordPress de manera independiente cuando sea necesario. Si vuestro plugin es orientado a objetos podréis pasar el objeto donde está ubicado el método a llamar para cada acción. En mi caso concreto, simterm.php contiene lo siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
<?php
/**
 * Plugin Name: SimTerm
 * Plugin URI:  http://gaspar.totaki.com/en/php-project/simterm/
 * Description: Simulates terminal input/output for tutorials
 * Version: 0.1.0
 * Author: Gaspar Fernández
 * Author URI: http://totaki.com/poesiabinaria/
 * License: GPL3
 */


require_once('views.php'); // visto en la primera parte

class SimTermLoader
{
    protected static $st;

    function Init()
    {
    /* Incluimos nuestra clase */
    $path = plugin_dir_path(__FILE__);
    require_once($path.'simterm-core.php');
    self::$st = new SimTerm;

    add_action('admin_menu', array(self::$st->settings(), 'register_settings_menu'));
    add_action('admin_init', array('SimTermLoader', 'settingsInit'));
    }

    public function settingsInit()
    {
    $sett = self::$st->settings();
    $sett->register();
    }
};

SimTermLoader::Init();

En este caso, Init() crea una instancia de SimTerm, que está en el archivo simterm-core.php (vimos algo en la primera parte). Ahora, el objeto donde están register_settings_menu y register lo obtenemos de la llamada a settings() de SimTerm. Por ahora, la clase SimTerm contiene lo siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<?php
require_once('simterm-settings.php');

class SimTerm
{
    protected $settings;

    function __construct()
    {
    /* Inicialización básica de mi plugin
       (la que no tiene que ver con WordPress) */

    $this->settings = SimTermSettings::getInstance();
    }

    function settings()
    {
    return $this->settings;
    }
};

Como vemos, ya que SimTermSettings es un singleton, con la llamada de SimTerm::settings() obtendremos la instancia de dicho singleton. La clase SimTermSettings, por el momento vacía está así:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
class SimTermSettings
{
    private static $instance;
    public static function getInstance()
    {
    if (self::$instance === null)
        self::$instance = new SimTermSettings();

    return self::$instance;
    }

    protected function __construct()
    {
    }

    private function __clone()
    {
    }

    private function __wakeup()
    {
    }
};

Comentamos ahora lo que tiene que hacer la función a la que llamamos en la acción admin_menu:

1
2
3
4
5
6
7
8
9
10
<?php
    public function register_settings_menu()
    {
    add_options_page('SimTerm Settings', 'SimTerm settings', 'administrator', 'simterm-settings',array($this, 'globalSettingsPage'));
    }

    public function globalSettingsPage()
    {
    echo SimTermView::render('globalsettings');
    }

Lo importante es add_options_page($titulo_de_la_pagina, $titulo_del_menu, $permisos, $slug, $callback) con el que se inserta el elemento en el menú de WordPress. Si preferimos un enlace más grande y no dentro de Ajustes podemos utilizar add_menu_page() con el que podemos poner hasta un icono.
Lo importante es que cuando se pulsa, se cargará la vista que está en views/globalsettings (mirar la clase SimTermView, para ver cómo va todo). Esta vista la pondré más adelante.

Por otro lado, tenemos el método register(), que explicaremos a continuación.

Empezamos con las opciones

Lo más básico para crear opciones de WordPress es:

No voy a detallar el funcionamiento de estas llamadas porque ya está muy bien documentado en el Codex de WordPress (ver los enlaces). Aunque voy a poner el caso concreto de SimTerm aquí para tener una idea y un ejemplo concreto de uso.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
<?php
    public function register()
    {
    /* Settings registration  */
    register_setting('simterm-settings',
             'simterm-default-theme');
    register_setting('simterm-settings',
             'simterm-delay-time',
             array($this, 'number_sanitize'));
    register_setting('simterm-settings',
             'simterm-command-prepend');
    register_setting('simterm-settings',
             'simterm-type-prepend');
    /* Config sections  */
    add_settings_section('simterm-global-settings',
                 'SimTerm Configuration',
                 array($this, 'globalConfiguration'),
                 'simterm-settings');

    /* Config fields */
    add_option('simterm-type-prepend', '>');
    add_option('simterm-command-prepend', '$#');
    add_option('simterm-default-delay', '400');
    add_option('simterm-default-theme', 'light');

    add_settings_field('simterm-default-theme',
               'Theme to use',
               array($this, 'config_default_theme'),
               'simterm-settings',
               'simterm-global-settings');
    add_settings_field('simterm-default-delay',
               'Delay between lines',
               array($this, 'config_default_delay'),
               'simterm-settings',
               'simterm-global-settings');
    add_settings_field('simterm-command-prepend',
               'Command prepend character',
               array($this, 'config_command_prepend'),
               'simterm-settings',
               'simterm-global-settings');
    add_settings_field('simterm-type-prepend',
               'Type prepend character',
               array($this, 'config_type_prepend'),
               'simterm-settings',
               'simterm-global-settings');
    }

    public function number_sanitize($value)
    {
    return (is_numeric($value))?$value:0;
    }

    public function globalConfiguration()
    {
    echo wpautop( "This are some options you can change." );
    }
    public function config_default_theme()
    {
    /* In the future, this themes may be extensions of this plugin  */
    echo SimTermView::render('settings/select', array('fieldId'=>'simterm-default-theme',
                              'options' => array('regular' => 'Regular',
                                         'dark' => 'Dark',
                                         'light' => 'Light',
                                         'blue' => 'Blue'),
    ));
    }

    public function config_default_delay()
    {

    echo SimTermView::render('settings/text', array('fieldId'=>'simterm-default-delay',
                            'fieldText' => 'Delay in milliseconds'
    ));
    }

    public function config_command_prepend()
    {
    echo SimTermView::render('settings/text', array('fieldId'=>'simterm-command-prepend',
                            'fieldText' => 'Any of these characters may prepend a command input'
    ));
    }

    public function config_type_prepend()
    {
    echo SimTermView::render('settings/text', array('fieldId'=>'simterm-type-prepend',
                            'fieldText' => 'Any of these characters may prepend a type input'
    ));
    }

En este caso registramos las siguientes configuraciones:

  • simterm-default-theme : Será el tema por defecto que coja el terminal. En principio habrá pocos temas, así que estarán codificados directamente en estos archivos. Si todo marcha bien y terminamos con 200 plugins habrá que pensar algo nuevo.
  • simterm-delay-time : Será la espera entre línea y línea. En el futuro habrá más opciones para esto.
  • simterm-command-prepend : Será el carácter que introducirá un comando (pondremos el prompt, que suele ser un dólar).
  • simterm-type-prepend : Será el carácter que introducirá una petición al usuario, pondremos un signo mayor que (>)

Todas las configuraciones pertenecen a simterm-settings, que lo creamos para la ocasión. El último parámetro de register_setting() es un callback que filtrará el dato obtenido de base de datos e impedirá que entren datos no válidos (o por ejemplo si agrupamos varios datos en una misma cadena de caracteres, o tenemos que hacer cualquier otro tratamiento)

Con respecto a las secciones, sólo tendremos una sección (por el momento), y principalmente llamará a la función globalConfiguration() que pondrá un texto en pantalla. Podríamos cargar una vista para poner más cosas, en el futuro creo que así será. Más adelante, definimos las opciones por defecto de cada una de las opciones de configuración. Y, por último, definimos los campos de formulario que se cargarán para cada opción de configuración definida y el texto introductorio de las mismas. En este caso, a add_settings_field le pasaremos:

  • Opción a modificar
  • Texto de introducción
  • Callback del campo (que como vemos, todas las funciones llaman a vistas (que pondré más adelante)
  • Página de configuración
  • Sección
  • Podemos pasar un array de argumentos para el callback y hacer funciones más genéricas.

Es cierto que podemos prescindir del tema de las plantillas de las vistas, fijaos como los callbacks lo único que hacen es presentar ciertas plantillas, código que podemos escribir directamente en dichas funciones PHP. Pero por manía mía desde hace años, y por tener algo más de flexibilidad y mejor mantenimiento me gusta tener todo lo relacionado con las vistas en otro lugar y por separado.

Y ya lo tenemos, generaremos una pantalla de configuración como esta:
Screenshot 28-07-2016-210714

Las vistas utilizadas

Adjunto también las vistas utilizadas, porque, aunque miréis el código fuente del plugin, tal vez éste haya cambiado con respecto a esta guía.

views/globalsettings.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<div class="section panel">
    <h1>SimTerm Options</h1>
    <form method="post" enctype="multipart/form-data" action="options.php">
        <?php
    settings_fields('simterm-settings');
        do_settings_sections('simterm-settings');
        ?>
        <p class="submit">  
            <input type="submit" class="button-primary" value="<?php _e('Save Changes') ?>" />  
        </p>  
       
    </form>
   
    <p>SimTerm by <a href="http://gaspar.totaki.com">Gaspar Fernández</a> using Show Your Terms by <a href="http://kandebonfim.com">Kande Bonfim</a>.</p>
</div>

views/settings/text.php

1
2
3
4
5
6
7
8
9
<label for="<?php echo $fieldId;?>">
   <input id="<?php echo $fieldId;?>" type="text" value="<?php echo get_option( $fieldId ); ?>" name="<?php echo $fieldId;?>" />
   <div class="settings-text-expl">
   <?php
    if (isset($fieldText))
      echo $fieldText;
   ?>
</div>
</label>

views/settings/select.php

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<select id="<?php echo $fieldId;?>" value="1" name="<?php echo $fieldId;?>">
   <?php
   if (isset($options))
     {
       $default = get_option( $fieldId, true );
       foreach ($options as $optionKey => $optionValue)
     {
       echo '<option value="'.$optionKey.'" '.selected($optionKey==$default).'>'.$optionValue.'</option>';
     }
     }
   else
     echo 'No options';
?>
</select>

Tercera parte

La tercera parte, que se publicará el día 29. Estará enfocada a la inclusión de recursos y a los shortcodes. Y aún queda mucho por recorrer.

The post Cómo crear un plugin para WordPress. Making of SimTerm: pantalla de configuración (segunda parte) appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Ingenieria de Software / Software Engineering / Project Management / Business Process Management

CRM | Una filosofia

August 19, 2016 11:52 PM

CRM: A Philosophy That Goes Beyond Data, Technology And Channel http://flip.it/Mf_b3Z

» Leer más, comentarios, etc...

Jesús Perales

Optimizando código con Eclipse IDE

August 19, 2016 09:16 PM

Optimizando código con Eclipse IDE

Existe una funcionalidad muy poco utilizada en los entornos de trabajo que e visto y no cuesta nada en activar en Eclipse IDE, esta funcionalidad permite remover las clases importadas no necesarias de nuestro código de forma automatica.

Para activar esta funcionalidad es necesario ir a Window --> Preference --> Java --> Editor --> Save Actions , marcamos la opción de Perform the selected actions on save y después la opción que dice Organize imports, para finalizar damos click en el boton de OK.

Optimizando código con Eclipse IDE

» Leer más, comentarios, etc...

Jesús Perales

K-means

August 18, 2016 03:11 PM

K-means

Hace tiempo hice una tarea en un antiguo blog que tengo en el que hablaba de k-means, asi que decidi rescatarla solo para recordar algo de algoritmos que e ido dejando de lado por el momento.

Introducción

K-means esta desarrollado por el principio de agrupamiento, el cual tiene principios básicos de características nítidas o difusas, ya que en base a un grupo de características K-means determina los grados de pertenencias de dichas características y los va separando por grupos similares.

Se pretende realizar un algoritmo el cual ordenar un array de vector con el principio de K-Means:

Se desarrollara en la entrada:

  • Introducción
  • Marco Teórico
  • Desarrollo
  • Resultados
  • Conclusiones

Marco Teórico:

Los argumentos son grupos de elementos, en los cuales cada grupo de elemento esa agrupado con características similares o especificas. No pueden aver agrupamientos con características diferentes.

Se pueden encontrar varios tipos de argumentos:

Jerárquico: De los grupos formados se crean grupos nuevos, así podrá obtener nuevos elementos de otros grupos.

Partición: Se miden los grados de pertenencias para ordenar en grupos los cuales llamaremos (centroides)

Difuso: Estas características tienen un grado de pertenencia numérico, y respecto este numero se podra ordenar en varios grupos que contengan ese grado de pertenencia similar.

Traslape : Se actualizan los datos ingresados del algoritmo.

Desarrollo

Se han utilizados las siguientes tecnologías al ser de fácil uso y por que me gustan los lenguajes script, en especial javascript

  • HTML
  • CSS
  • Javascript

Creamos una librería llamada KMeans la cual contiene las siguientes funciones:

recorrerPuntos: Nos sirve para saber que valores tienen los puntos dados solo para cuestiones de debug


calcularDist : Hace las operaciones correspondientes para calcular la distancia euclidiana


obtenerDist: obtiene la distancia euclidiana de una serie de puntos dados implementando la función calcularDist.


agrupamiento: Agrupa los puntos a cierto grupo dependiendo de su distancia euclidiana con los centroides


recalcularCent: Hace las operaciones correspondientes para obtener un nuevo valor para cada par de centroides.

Resultados

Los resultados los mostramos en una serie de tablas en las que se observa cada uno de los elementos y datos que el algoritmo necesita como son las coordenadas en "x" y en "y" de los puntos y de los centroides, las distancias euclidianas calculadas,los grupos que se formaron y los centroides re-calculados, desafortunadamente aun no encuentro alguna herramienta que permita graficar fácilmente, por lo que es una cuestión pendiente.

K-means

K-means

Conclusión

K-means sirve para agrupar arrays, tiene de cierta manera similitud con el método Burbuja y Quicksort, mas aun asi K-means también es una opción muy valida para el ordenamiento de vectores.

Descargar codigo

» Leer más, comentarios, etc...

Adrianistán

Programando para Haiku – Barras de menús – Parte III

August 17, 2016 07:05 PM

Seguimos con los tutoriales de Haiku, hoy veremos como crear barras de menú. Partimos del código de la ventana vacía, lo tienes en la foto junto con el comando de compilación.

MiAplicacionHaikuCodigoHaz click en la imagen para verlo en grande

Debemos saber que en la API de BeOS hay tres clases que nos van a servir.

  • BMenuBar, se trata de la barra en sí, que esta pegada a la ventana. Un BMenuBar contiene BMenus.
  • BMenu, son los menús en sí. Un menú es un elemento que contiene acciones, organizadas como si fuera una lista. Los menús no definen acciones, pero sí su organización. Así, a un BMenu le tendremos que añadir BMenuItems u otro BMenus (menús anidados).
  • BMenuItem, son las acciones de los menús. Cada BMenuItem tiene la capacidad de generar un BMessage nuevo, listo para ser procesado por nuestra aplicación.

En la imagen se puede ver perfectamente

BMenu

Vamos a crear una barra de menú con dos menús, uno de ellos simple y otro con un menú anidado y un separador.

#include <AppKit.h>
#include <InterfaceKit.h>
#include <InterfaceDefs.h>

#define NEW_FILE 3
#define EXPORT_AS 5

class VentanaPrueba : public BWindow{
	public:
		VentanaPrueba() : BWindow(BRect(100,100,900,700),"Mi ventana",B_TITLED_WINDOW,0){
			AddChild(CreateMenuBar());
		}
		bool QuitRequested(){
			be_app_messenger.SendMessage(B_QUIT_REQUESTED);
			return BWindow::QuitRequested();
		}
		void MessageReceived(BMessage* msg){
			switch(msg->what){
				default:
					BWindow::MessageReceived(msg);
			}
		}
		BMenuBar* CreateMenuBar(){
			BMenuBar* bar = new BMenuBar(BRect(0,0,100,20),"MenuBar");
			
			BMenu* file = new BMenu("File");
			BMenu* help = new BMenu("Help");
			BMenu* exportMenu = new BMenu("Export");
			
			bar->AddItem(file);
			bar->AddItem(help);
			
			/* FILE */
			BMenuItem* newFile = new BMenuItem("New file",new BMessage(NEW_FILE));
			newFile->SetShortcut('N',B_COMMAND_KEY);
			file->AddItem(newFile);
			
			file->AddItem(exportMenu);
			file->AddSeparatorItem();
			
			BMenuItem* quit = new BMenuItem("Quit",new BMessage(B_QUIT_REQUESTED));
			quit->SetShortcut('Q',B_COMMAND_KEY);
			file->AddItem(quit);
			
			/* EXPORT */
			BMenuItem* exportAs = new BMenuItem("Export as...",new BMessage(EXPORT_AS));
			exportMenu->AddItem(exportAs);
			
			/* HELP */
			BMenuItem* helpVersion = new BMenuItem("Help",NULL);
			help->AddItem(helpVersion);
			
			return bar;
		}
};

class AplicacionPrueba : public BApplication{
	public:
			VentanaPrueba* ventana;
			AplicacionPrueba() : BApplication("application/x-aplicacion-prueba"){
				ventana = new VentanaPrueba();
				ventana->Show();	
			}
};

int main(int argc, char** argv){
	AplicacionPrueba app;
	return app.Run();
}

Y el resultado es el siguiente:

BMenuBar

Como vemos, SetShortcut hace que los menús sean seleccionables con combinaciones de teclado. Hay que tener en cuenta que en BeOS, la tecla que en Windows normalmente Ctrl, es Alt. Así operaciones como copiar y pegar con Alt+C y Alt+V. Para responder al evento solo hace falta escuchar en la función MessageReceived. En el caso de B_QUIT_REQUESTED, el mensaje ya está implementado en la función QuitRequested.

La entrada Programando para Haiku – Barras de menús – Parte III aparece primero en Blog - Adrianistan.eu.

» Leer más, comentarios, etc...

Adrianistán

Beta privada de TucTum, la red social que te paga

August 15, 2016 10:18 AM

Hace poco me enteré de que Tsu, la red social que pagaba a sus usuarios una parte de lo que generasen por publicidad, había cerrado. Me lo comentó un amigo, había intentado acceder desde la app de Android y ya no podía. Efectivamente, Tsu había cerrado. Llevaba acumulados unos cuantos euros (6 o 7 euros) y me sentó mal, porque además no han explicado los motivos del cierre. Había que hacer algo.

TucTum

Me gustaría inventar algo como Tsu, que permitiese a la gente compartir y hacer amigos mientran ganan dinero. Pero solo soy una persona, hacer una red social desde cero sería demasiado complicado. Entonces recordé GNU Social, una red social que suelo usar y cuyo código fuente está disponible. GNU Social está hecho en PHP, pero además tiene una completa API de plugins, por lo que no he tocado el código central de la red social, solo he diseñado un plugin que permite a los usuarios ganar dinero.

TucTumHome

Se paga por cada favorito que recibas (obviamente la multicuenta estará baneada), cuando tengas 1.000.000 de satoshis puedes recibir el pago en Bitcoin. La cantidad de satoshis que da TucTum por cada favorito es algo que quiero estudiar. Por una parte quiero dar lo máximo posible pero que me permita mantener el servidor. En TucTum tampoco se pueden subir imágenes. Esto es algo temporal, si veo que TucTum despega habilitaré la subida de archivos multimedia. De momento recomiendo usar Imgur, del mismo modo que se hace en Reddit.

Otra característica es el acortamiento de enlaces usando ShortKin.gq, también de mi propiedad.

Beta privada

TucTum entra en Beta privada, limitada por invitaciones. Voy a repartir 100 invitaciones entre la gente de este blog para registrarse en TucTum e intentar ganar dinero. Estas 100 personas podrán invitar a quien quieran a la red social, aunque aviso que todavía no hay sistema de referidos, por lo que no habrá reparto de beneficios por invitar a alguien.

Para pedir tu invitación puedes hacer lo siguiente:

No hace falta que hagas las tres cosas, con que hagas una ya vale. Mientras uséis TucTum es interesante ir comunicándome vuestras sensaciones, que podría mejorar, que esta bien, que esta rematadamente mal,etc

La entrada Beta privada de TucTum, la red social que te paga aparece primero en Blog - Adrianistan.eu.

» Leer más, comentarios, etc...

Poesía Binaria

Cómo crear un plugin para WordPress. Making of de SimTerm (primera parte)

August 15, 2016 08:39 AM

simterm
Son muchos los plugins para WordPress disponibles hoy en día, aunque la magia de este sistema de publicación radica en sus posibilidades para extenderlo. Así que aquí contaré la historia de la primera versión de mi primer plugin más o menos serio para WordPress: SimTerm. Contando, los pasos que di, lo que pude haber hecho de otra forma y lo que debí haber hecho de otra forma.

Índice

  1. Instalación local de WordPress.
  2. Elección del nombre.
  3. Creando nuestro plugin
  4. Pequeña intro a la programación de plugins
  5. Vistas

Instalación local de WordPress

Lo primero, siempre que nos embarquemos en este tipo de proyectos será instalar WordPress de manera local, en nuestro ordenador. Así iremos mucho más rápido. En ningún caso recomiendo trabajar en remoto editando los archivos en el servidor. Conozco casos de otros desarrolladores que argumentan que así van más rápido pero:

  • Si trabajas a través de un FTP, debes contar el tiempo que tarda una conexión en establecerse y un archivo en subirse. Crear o modificar un plugin es una tarea que implica salvar muchísimas veces los archivos y tal vez eches entre 5 y 10 segundos extra cada vez que salves y tengas que probar el archivo.
  • Si trabajas con sesiones SSH, en ocasiones los servidores no responden inmediatamente como si estuvieras en local, por lo que pequeños retardos en las respuestas del editor de texto pueden causarte una pérdida grande de tiempo global.
  • Si trabajas desde un editor desde la misma web, aunque los hay muy eficientes, pero siempre hay que hacer un envío de información con los contenidos del archivo que implica un tiempo de envío.
  • Cuando pruebes la web, un servidor de Internet, tal vez tarde uno o dos segundos más (en el mejor de los casos) en responder, que suma al tiempo perdido editando.
  • Te quedas sin Internet un momento, y no puedes trabajar.
  • La depuración puede ser horrible, Muchos servidores están configurados para ocultar todos los errores. Así que sólo veremos pantallas vacías o de errores de servidor que no nos dirán nada. Por otro lado, si configuramos el servidor para poder visualizar correctamente los errores, todo el mundo podrá verlos.
  • Volviendo a lo de antes, si todo el mundo puede ver los errores, también verá los progresos, y las páginas rotas constantemente, por lo que perderemos visitas a nuestro sitio (o nuestro cliente perderá sus visitantes), lo que tampoco es recomendable.

Así que, antes de nada, instalemos en local un WordPress vacío, si nuestro plugin necesita dependencias, instalémosle también éstas. O si nuestro proyecto es para un cliente y necesitamos adaptarnos a su WordPress tal y como está ahora, siempre podemos migrar la instalación a nuestro servidor local.

Para este caso, yo utilicé WP-CLI, con el que realicé una instalación de WordPress en mi ordenador. Primero creé un usuario en MySQL (podríamos utilizar nuestro root, que es local y no pasa nada, pero yo prefiero tener todo organizado):

> CREATE SCHEMA wptest
Query OK, 1 row affected (0.00 sec)
> GRANT ALL PRIVILEGES ON wptest.* TO ‘wptest’@’localhost’ IDENTIFIED BY ‘12345’;
Query OK, 0 rows affected (0.00 sec)

Ahora, instalé WordPress de la siguiente manera:

$ wp core download –path=wptest –locale=es_ES
Downloading WordPress 4.5.3 (es_ES)…
md5 hash verified: d991b3152a1649b1286fd076658e1066
Success: WordPress downloaded.
$ wp core config –dbname=wptest –dbuser=wptest –dbpass=12345 –dbhost=localhost –locale=es_ES
Success: Generated wp-config.php file.
$ wp core install –url=”http://localhost/wptest/” –title=”WP Tests” –admin_user=”admin” –admin_password=”pass” –admin_email=”blakeyed@totaki.com”
Success: WordPress installed successfully.

Si utilizar MySQL sandbox, tendrás el motor de base de datos instalado en otro socket, o puerto diferente, en mi caso, tengo la base de datos que utilizo en /tmp/mysql_sandbox5167.sock así que, para instalar WordPress ahí, tengo que decir:

dbhost=localhost:/tmp/mysql_sandbox5167.sock

Y ya tendría la base de datos lista.

Elección del nombre

Tampoco es nada del otro mundo. Pero debemos procurar que sea descriptivo y no esté siendo utilizado por otro plugin de WordPress. En principio, ya que el plugin va a servir para simular un terminal (de Linux o de cualquier otro SO), simterm me pareció un buen nombre (porque WP-Terminal estaba cogido).
Para ver si el nombre está cogido, debemos crear un slug, o un título corto que utilice caracteres seguros, en este caso coincide con el nombre “simterm”, pero podría ser wp-simterm, wordpress-sim-term o algo así. Para ver si el slug está cogido, podemos acceder a https://wordpress.org/plugins/[slug] y ver si hay algo ahí.

El hecho de que el nombre no esté siendo utilizado por otro, es más que nada para que nos encuentren fácilmente. Si otro se llama igual, puede haber confusión por parte de los usuarios. El hecho de que el slug no esté cogido, además de para poder subirlo a WordPress.org va a hacer que no haya conflicto con otros plugins y como la vida de una página en WordPress es larga, no sabemos qué plugins vamos a instalar. Me refiero sobre todo al hecho de crear un plugin privado (que no vamos a liberar) que se llame igual que otro plugin que hay instalado.

Creando nuestro plugin

Lo primero que hacemos es crear un directorio donde estará nuestro plugin. Lo crearemos dentro de wp-content/plugins/ y se llamará simterm.
Una vez hecho esto, creamos un archivo que se llame igual que el directorio que acabamos de crear, pero con extensión php, e incluimos lo siguiente:
wp-content/plugins/simterm/simterm.php:

1
2
3
4
5
6
7
8
9
10
<?php
/**
 * Plugin Name: SimTerm
 * Plugin URI:  http://gaspar.totaki.com/en/php-project/simterm/
 * Description: Simulates terminal input/output for tutorials
 * Version: 0.1.0
 * Author: Gaspar Fernández
 * Author URI: http://totaki.com/poesiabinaria/
 * License: GPL3
 */

Será un comentario de PHP muy grande con información básica sobre el plugin.

En este mismo instante, nuestro plugin ya debe aparecer en la sección de Plugins de WordPress:
myplugin

Pequeña intro a la programación de plugins

WordPress permite hacer los plugins de la forma que queramos, podemos empezar a escribir funciones y llamadas a la API de WordPress sin parar, aunque debemos hacer el plugin también bonito por dentro. Esto es subjetivo, pero tras leer varios plugins de WordPress de otras personas, hay una forma que me parece sencilla para empezar y a la vez elegante para crear nuestro plugin.
En el mismo archivo principal del plugin (simterm.php) empezaremos creando una clase SimTermLoader, con varios métodos, uno de ellos será Enable() o Init() donde tendremos todas las llamadas necesarias a funciones de WordPress para inicializar nuestro plugin: configuración de pantallas de administración, idiomas, shortcodes, hooks, etc, así como carga de ficheros, instanciación de clases. Las funciones que llame WordPress de nuestro plugin serán ahora de una clase SimTerm que crearemos en un archivo llamado (simterm-core.php, o podremos llamarla nuestroplugin-main.php, nuestroplugin-base.php, etc.).
Y lo primero que haremos nada más cargar el plugin será llamar de forma estática a este método SimTermLoader::Init()

La estructura básica será la siguiente:

1
2
3
4
5
6
7
8
9
10
11
12
13
class SimTermLoader
{
  function Init()
  {
    /* Incluimos nuestra clase */
    $path = plugin_dir_path(__FILE__);
    require_once($path.'simterm-core.php');
    $st = new SimTerm;
    /* Acciones de WordPress add_filter, add_option, register_option... */
  }
};

SimTermLoader::Init();

wp-content/plugins/simterm/simterm-core.php:

1
2
3
4
5
6
7
8
9
10
11
<?php
class SimTerm
{
  function __construct()
  {
    /* Inicialización básica de mi plugin
       (la que no tiene que ver con WordPress) */

  }

  /* funciones callback para operaciones del plugin */
};

Algunos autores prefieren que la clase principal de su plugin (SimTerm en mi caso) sea de tipo Singleton. De ese modo todas las acciones y callbacks de WordPress irán a métodos de la clase SimTermLoader y ésta obtendrá la instancia del Singleton SimTerm y llamará al método adecuado.

Vistas

Los plugins producirán una salida de cara al usuario. Y personalmente no me gusta mezclar los archivos PHP de un plugin con salidas HTML del usuario. Por eso, vamos a colocar un pequeño sistema de vistas, no muy elaborado, pero evolucionará. Con este sistema conseguiremos separar la salida del usuario de los propios archivos del plugin haciendo más fácil su mantenimiento y más ordenado.
Estas vistas, las colocaremos dentro del directorio del plugin, en un directorio llamado views. Y haremos algo muy parecido a lo que hace get_template_part() en los temas, pero para nuestro plugin. Para ello, incluiremos dentro del archivo principal del plugin (simterm.php) el archivo views.php cuyo contenido es:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?php

class SimTermView
{

  public static function render($slug, $variables=array(), $name = null)
  {
    global $wp_query;

    $template = self::searchTemplate($slug, $name);

    if ( is_array( $wp_query->query_vars ) )
      {
    extract( $wp_query->query_vars, EXTR_SKIP );
      }

    extract($variables);

    ob_start();

    if ( $template )
      require( $template ); /* load_template just requires or require_once the file extracting wp_query vars */

    return ob_get_clean();
  }

  private static function searchTemplate($slug, $name)
  {
    $templateNames = array();
    $path = plugin_dir_path(__FILE__).'/views/';

    if (isset($name))
      $templateNames[] = "{$slug}-{$name}.php";

    $templateNames[] = "{$slug}.php";

    foreach ( (array) $templateNames as $template )
      {
    if (!$template)
      continue;

    if (file_exists($path . '/' . $template))
      return $path . '/' . $template;
      }

    return false;
  }

};

Por lo tanto, a partir de ahora, siempre que queramos incluir algo de HTML (un poco de PHP también se permite, pero cuidaremos que éste sea sólo para generar salidas HTML para el usuario), lo escribiremos todo en un archivo aparte que situaremos dentro de views/ y lo llamaremos:

slug.php

o

slug-name.php

Siendo slug y name dos palabras que identificarán nuestra vista. Nuestro plugin buscará la plantilla y la volcará a pantalla usando la API de WordPress.
Además, tenemos un array llamado variables, que será asociativo y contendrá las variables que representaremos más tarde dentro de la vista. Así si hacemos:

1
2
<?php
echo SimTermView::render('mivista', array('nombre' => 'Poesía Binaria', 'url' => 'http://totaki.com/poesiabinaria/'));

La vista podrá contener algo parecido a esto:

1
<a href="<?php echo $url; ?>" title="<?php echo $nombre;?>"><?php echo htmlentities($nombre); ?></a>

Preparados para la segunda parte

El 22 de agosto saldrá la segunda parte de esta introducción a la creación de plugins de WordPress con mucho más contenido, enfocado a las páginas de configuración, a la inclusión de archivos CSS y JS a la web y a la creación del shortcode que utilizará este plugin.

The post Cómo crear un plugin para WordPress. Making of de SimTerm (primera parte) appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Blog Bitix

Eligiendo proveedor de internet, finalmente Pepephone

August 14, 2016 08:30 PM

Cada unos de los operadores de telecomunicaciones más conocidos e importantes ofrecen internet ya sean con fibra óptica, ADSL o incluso 4G. Junto con la forma de ofrecer internet que en la mayoría es mediante fibra las diferencias están en el precio y las diferencias son significativas. En este artículo comentaré que opciones he barajado y por cual me he decidido finalmente.

Pepephone

Después de hacer unos cuantos temas ha llegado el turno de elegir un proveedor de internet. Como en todos los casos en los que hay que tomar alguna decisión he empezado por recopilar que opciones ofrece cada compañía, con que características y precios. Hay diferencias importantes entre algunas de las ofertas de los operadores que dependiendo de nuestras necesidades alguna se adaptará mejor, no hay una oferta que de forma absoluta sea la mejor aunque puede que si para una mayoría.

Mis necesidades era simplemente de internet sin combinar con algún plan de móvil, así que con este simple requisito empecé a informarme. Varios operadores ofrecen internet ya sea con ADSL si no tienen cobertura de fibra entre ellos Movistar, Vodafone, Orange, Amena, Pepephone o Euskaltel. De entre estos debía buscar la oferta que más me convenciera. Una de las primeras diferencias que encontré y que me llamaron la atención aunque ya estaba informado es que en los casos de Pepephone y Amena ofrecen una modalidad de internet sin teléfono fijo lo que evita el abultado coste de la línea o ya está incluido en el precio haciendo que sean algo más baratas. Todas las ofertas que vi del resto de operadores incluían la instalación del obsoleto teléfono fijo que en mi caso no iba a utilizar. Como con el móvil tengo más que suficiente para llamadas de voz las opciones de Amena y Pepephone que no necesitan instalar teléfono junto con el precio ya era un par de buenos motivos para posicionar las opciones.

Aún con dos buenos motivos revisé cuales eran los precios de cada uno de los operadores. Conociéndolos la verdad es que algunos operadores se exceden en sus precios. ¿60€ o más mensuales por tener internet? Por mucho ancho de banda simétrico y megas que ofrezcan me parecía muy caro, además aún descargando mediante P2P gran cantidad de cosas es innecesario la cantidad de ancho de banda que ofrecen. 300, 100, 50, incluso 30 o menos son más de lo que necesita un porcentaje altísimo de gente para navegar por internet e incluso para hacer un uso moderado descargas por P2P el menor ancho de banda contratable es suficiente. No se quien necesitará 300 megas simétricos de bajada y subida para uso residencial, me parece más que una necesidad publicidad para endosar una factura de más de 60 €/mes a los clientes.

Estos son los precios aproximados finales y fuera de promociones que los operadores mayoritarios se encargan de ocultar con promociones durante unos meses para desinformar a sus futuros clientes. Salvo Pepephone y la opción de Amena en casa que lo dejan bastante claro además de ser de los mejores precios.

Así que las opciones mejor posicionadas como candidatas era el ADSL de Pepephone o la opción de Amena en casa, sin teléfono fijo y de las opciones más baratas que hay. Comparando estas opciones la de Amena en casa me gustaba que no necesitaba instalación ya que funciona las redes de telefonía 4G al igual que los móviles ofreciendo velocidades similares a la fibra y mayores incluso que el ADSL. En contra de Amena en casa es que es unos 6 euros al mes más cara que el ADSL de Pepephone y que tiene un límite de tráfico de 40 GiB mensuales que no creo que la mayoría de meses superase pero alguno que hiciese descargas con P2P o alguna descarga directa puede que si, superando ese límite de tráfico no se incurre en ningún gasto adicional pero se limita la velocidad a unos ridículos 128 Kbps. Por los mismos motivos a favor de el ADSL de Pepephone tenía el precio y en su contra que necesita instalación de línea nueva que cuesta unos 90 € mas 39 € del coste del router ADSL, aunque adquirir el router es opcional y nos puede servir el de algún otro operador si ya disponemos con anterioridad, yo no tenía. Con Pepephone el coste de instalación y el router llega a 129 € con iva incluido, la opción de Amena en casa solo tiene el coste del router que es de 59 €. Una diferencia de 70 € que con el menor precio de Pepephone se compensa en 12 meses (mucho antes si lo comparamos con otra opción), 15 si incluyésemos el que nos diésemos de baja en Pepephone y la línea que tendría un coste administrativo de 18€. Finalmente por el precio de 23,6 € al mes, por no tener límite de tráfico y por su forma de trato a sus clientes me decidí por Pepephone. El coste inicial es significativo pero pasados unos meses compensa.

Otro aspecto de Pepephone que me gustaba es el reconocimiento en el trato que ofrecen a los clientes que ellos mismos destacan. Mi experiencia anterior era con Euskaltel y estos tienen la mala costumbre cada año sin que lo pidas subir los megas pero también la factura. En vez de más megas preferiría internet más barato, los accionistas de esa empresa al igual que otras no deben pensar lo mismo. Me parece que los operadores dominantes tratan de exprimir a sus clientes con «ofertas» envenenadas, ahora están con las que incluyen televisión de pago y el fútbol. Los incautos se darán cuenta de que les llegan facturas de entre 50 y 80 euros mensuales, alguien tiene que pagar (que no cuenten conmigo) las obscenas fichas y cláusulas de rescisión de las estrellas del fútbol aunque sean condenados a 21 meses de cárcel por fraude fiscal.

Volviendo a Pepephone, el router ADSL2+ que proporciona Pepephone está bastante bien en el momento de mi contratación es un ASUS DSL-N14U del que en RedesZone han hecho varios artículos con un análisis muy detallado. Estas son su características principales:

  • WiFi 802.11 b/g/n de hasta 300 Mbps
  • Cuatro puertos Fast-Ethernet
  • Un puerto USB 2.0
  • 64 MB memoria RAM y 16 MB de memoria flash
  • CPU Ralink RT63365E
  • Soporta descargas por torrent y compartición con CIFS/SAMBA, FTP, DLNA, VPN PPTP

Artículos analizándo el router ASUS DSL-N14U:

Solicitada la instalación en unos días un técnico de Movistar me instaló la línea nueva (linea que realmente es de Vodafone) y el router me llegó por mensajero al día siguiente, en una semana ya disponía de internet sin complicaciones en la instalación. La velocidad bruta no es la misma que tenía con el cable de Euskaltel y será menor que la fibra pero para navegar no hay mucha diferencia y si en el precio. Como dice Pepephone el ADSL es algo más feo que la fibra y tiene razón de que hay mucha tontería con los megas, para navegar no noto apenas diferencia. Lo noto cuando actualizo Arch Linux o cuando pongo la Raspberry Pi a descargar por P2P. Aún llegando solo a 630 KiB/s en la descarga cuando con Euskaltel llegaba a 2 MiB/s me es más que suficiente, la RPi la dejo el tiempo que haga falta y en unas horas no hay película que no pueda descargar y la actualización de Arch lleva algo más de tiempo en la descarga pero no algo excesivo.

Test de velocidad de ADSL Pepephone

Estos 9 MiB de bajada y 400 KiB de subida son algo menos de la mitad teórica del ADSL y en algunas pruebas de velocidad que he hecho me ha dado resultados de 4 MiB / 200 KiB pero aún en el peor de los casos en la navegación no es perceptible. Respecto a la estabilidad de la linea sin ningún problema, en las pruebas de ping que he hecho no se pierden paquetes. Esta menor velocidad que la teórica es algo que no era una sorpresa para mí que ya me lo esperaba aunque pensaba que sería algo mejor y como he comentado la velocidad no es a lo que más importancia le he dado, si al precio.

Router ADSL de Pepephone

» Leer más, comentarios, etc...

Blog Bitix

Por qué guardar las fechas en UTC en la base de datos

August 14, 2016 12:30 AM

Java
PostgreSQL

Es rara la aplicación que trabajado con bases de datos no maneje fechas, quizá es menos habitual aplicaciones que trabajan con fechas y diferentes horarias, esto es haciendo alguna conversión entre zonas horarias. Si se nos presenta el caso de trabajar con fechas y diferentes zonas horarias haremos bien en hacer que las fechas que guardemos en la base de datos estén en la misma zona horaria al menos y convertirla posteriormente a la zona horaria que necesite la aplicación. UTC además de ser una zona horaria neutra evita el problema de que algunas bases de datos o lenguajes de programación para los campos fecha no guarda las zonas horarias con lo que puede ocurrirnos que guardemos la fecha en una zona horaria y la recuperemos en otra produciendo posiblemente incoherencias en las fechas por una hora.

¿Por qué elegir UTC?

Principalmente porque es una zona horaria neutra, universal y que elimina ambigüedades ya que que no tiene DST o horario de verano y podremos guardar las fechas sin temor a que al recuperarlas estén en otra zona horaria si la base de datos o el lenguaje de programación para guardarlas no las soporta.

Otros motivos que se mencionan en un comentario en inglés Always store dates/times in UTC (in the database) y algún otro en DateTime values should always be stored in UTC son que:

  • Calcular duraciones de tiempo es simple. El periodo de tiempo entre la 2:30 AM UTC y las 3:30 AM UTC es siempre una hora cosa que no ocurre en las horas que hay cambio de horario pudiendo ser el periodo entre cero y dos horas.
  • No hay fechas inválidas cuando se adelanta la hora por ejemplo de las 2:00 AM a las 3:00 AM, pudiendo ser que las 2:30 AM en esa zona horaria no exista.
  • Se evitan problemas al ordenar o agrupar fechas pudiendo ser el caso de que una fecha con tiempo 2:59 AM sea antes que las 2:01 AM por causa del cambio horario.
  • Los cambios horarios están sujetos a cambios nada predecibles y varían a lo largo del tiempo con relativa frecuencia con lo para calcular de forma fiable cuantas horas hay entre dos fechas se necesita guardar las variaciones históricas de DST. Ni las fechas de cambios DST son constantes ni las zonas horarias se mantienen fijas para las localizaciones.

Una vez recuperada la fecha en UTC podemos convertir de diferentes formas una fecha de una zona horaria a otra en Java y en cualquier otro lenguaje con las facilidades que proporcione según la zona horaria a visualizar la fecha.

¿Cúal es el caso que puede dar problemas?

Uno en el que la hora a guardar coincida con un cambio de hora de la zona horaria en la que guardemos las fechas. Por ejemplo, en España el año 2016 el cambio de horario de verano (DST/CEST) a horario de invierno (CET) se hará el 30 de octubre momento en el que a las 3:00 (CEST) volverán a ser las 02:00 pero con diferente zona horaria (CET).

Ejemplo

Supongamos que tenemos la fecha 30 de octubre a las 02:30 CEST y la guardamos en la base de datos pero sin la zona horaria pasando a estar implícita. En esta fecha y hora se produce un cambio horario de horario de verano a horario de invierno en España. Al recuperar la fecha será 30 de octubre a las 02:30 CET, la diferencia está entre el CEST y CET o la diferencia horaria +02:00 y +01:00. Una hora de diferencia entre la original y la que recuperamos de la base de datos después de hacer la conversión.

Esto puede probarse con el siguiente ejemplo de código de un programa Java que guarda y recupera de una base de datos PostgreSQL una fecha que está en el intervalo de cambio horario. En el ejemplo utilizaré Docker.

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/795512b5f0cb61bf88b16dfff519f4e7/raw/Main.java">Main.java</pre></a></noscript>
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/795512b5f0cb61bf88b16dfff519f4e7/raw/System.out">System.out</pre></a></noscript>
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/795512b5f0cb61bf88b16dfff519f4e7/raw/docker-compose.yml">docker-compose.yml</pre></a></noscript>

Tabajar con fechas no es simple, es muy curioso y no debemos hacer suposiciones sobre las fechas que son incorrectas en las aplicaciones.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando cd misc/docker/postgresql/ && docker-compose up && ./gradlew run.

» Leer más, comentarios, etc...

Bitácora de Javier Gutiérrez Chamorro (Guti)

Tecnología, productividad y sueldos

August 13, 2016 05:24 PM

Nos encontramos es un mundo que ya es casi completamente digital, algo que sorprendería incluso a Claude Shannon. Y si antaño, la acumulación de conocimiento se conseguía gracias a la palabra, ahora lo hace gracias a la tecnología. Suena bien, pero vamos a necesitar cambiar mucho. Nada que ver con las imágenes de un futuro […]

» Leer más, comentarios, etc...

Navegapolis

Cocina IKEA: un proyecto ingestionable, y la peor experiencia de usuario de mi vida.

August 09, 2016 01:47 PM

ikea[English]

Quizá este post sea simple catarsis: una arcada de desahogo al contar la amargura de esta pesadilla. O quizá sea un desquite con el que devolver fastidio por fastidio. Es posible que sea una constructiva y bienintencionada crítica para contribuir a la mejora de Ikea, o prevenir a futuros compradores de cocinas allí.

Seguramente es un poco de todo, y aunque para mi resulte muy perturbador, lo cierto es que tan sólo es un número más en las ventas de Ikea. No sé si el trato que estoy recibiendo es la excepción o la norma de esta empresa, simplemente lo comparto como una opinión más de las vertidas en la Red, y ya entre todas se verá si es norma o excepción.

Esta es la crónica de los hechos, que yo llamaría agravios, pero que con el proposito de ser lo más objetivo posible dejaré en hechos y me ahorraré comentarios y valoraciones 

Antecedentes.

  • 22-junio-2016 - PRE-COMPRA: Elección en la tienda Ikea de Zaragoza de muebles y electrodomésticos de una cocina completa.
  • 29-junio-2016 - VERIFICACIÓN de un técnico de Ikea en mi domicilio. Tras las oportunas comprobaciones concluye que la cocina es "apta para montaje" (Albarán MOBEL 50631).
  • 30-junio-2016 - CONFIRMACIÓN DE LA COMPRA: Verificado por Ikea que los muebles y electrodomésticos elegidos se pueden montar en mi domicilio, formalizo y pago la compra (nº iSell 756390981).

Mi objetivo es aprovechar el periodo de vacaciones en el que estará la casa vacía para realizar reformas de albañilería y cambiar la cocina. Para evitar problemas de fechas en las agendas de instalación de Ikea, realizo la compra con un mes de antelación. El calendario que refleja Ikea en el documento de compra venta  iSell 756390981 es:

  • Almacenaje de la compra del 1 al 26 de julio.
  • Transporte el 26 de julio de 14 a 18h.
  • Montaje el 27 de julio de 8 a 17h.

Relación de informalidades y agravios

26 de julio.

  • Tras desplazarnos a la casa que está en obras, a las 2 de la tarde para recibir los muebles, a las cuatro llama el transportista desde un teléfono anónimo (al que no podremos volver a llamar para preguntar nada) avisándonos de que no puede llegar hasta las 6 o 6 y media. Estuvimos esperando en una casa en obras sin más asiento que una escalera hasta las 10 de la noche, que es cuando llegó el transporte.

27 de julio

  • Tras otro desplazamiento a la casa en obras para el montaje de la cocina, tuvimos que esperar desde las 8 de la mañana (hora comprometida) hasta las 3 y media de la tarde, que fue cuando llegó el montador.
    No pudo montar la cocina porque el transporte había olvidado bastantes cosas, así que dejó algunos armarios montados y el instalador (Julián) nos informó que pasaba el parte de incidencia a Ikea. Que en 24 o 48 horas nos llamarían y darían la fecha para terminar el montaje. Nos advirtió que sobre todo no llamáramos nosotros a Ikea porque entonces se abrirían 2 incidiencias sobre el mismo montaje y podría dar problemas (dejemos los comentarios sobre un proceso de incidencias incapaz de detectar que dos peticiones son de la misma compra).

... pasadas 72 horas laborables sin recibir la prometida llamada en 24/48 horas ...

1 de agosto

  • Llamamos a atención al cliente de Ikea (900 400 922): No tienen conocimiento de ninguna incidencia. Les consta que la cocina está montada y terminada (?). Piden disculpas y nos informan de que en 24 / 48 horas nos llamarán para concretar el montaje.

2 de agosto

  • Volvemos a llamar a atención al cliente, sobre las 18h. Una persona se identifica como Ana y atiende amablemente la llamada. No le consta la incidencia, ni la llamada de ayer (?). Me dice que en 24 / 48 horas nos llamarán para concretar el montaje. Le ruego que agilice, no el montaje, sino simplemente darme la información de cuándo podrán montar la cocina, para poder tomar decisiones de si continuo alargando la estancia fuera de mi casa y por cuántos días. Me responde que no puede hacer nada más que poner en la incidencia que es urgente. Le pido una referencia para poder darla si tengo que volver a llamar. El nº que me da es el 12038241

3 de agosto

  • Volvemos a llamar sobre las 19h. Me atiende quien se identifica como Adrián, informándome de que no les consta por parte del instalador que la cocina esté sin montar, ni qué muebles faltan (?)... que en 24 o 48 horas me dirán cuándo pueden instalar la cocina.

4 de agosto

  • Nos desplazamos hasta la tienda Ikea de Zaragoza para poder hablar en persona con alguien de atención al cliente. De 13 a 14h. nos atiende Ana Cristina. En el sistema de CRM no les constan las llamadas y lo único que ve es la lacónica anotación de alguien de los que nos ha atendido por teléfono: "Llama el cliente - buenas tardes - tiene mucha prisa". Tras una hora de gestiones de Ana Cristina, la empresa de montaje promete localizar la incidencia y la lista de muebles que faltaban en cuestión de un rato para desatascar la situación.  ... Nos vamos a comer....  A las 2 horas nadie ha localizado nada y nos atiende María de 15:45 a 16:45, hora en la que nos tiene que dejar para relevar a una compañera en el departamento de textil. De 16:45 a 18h. nos atiende Ruth. Tras más de 4 horas de gestiones en el departamento de atención al cliente, Ikea nos entrega la orden de transporte y montaje nº iSell 768428228 con el compromiso "fijo, fijísimo" de que el lunes 8 de Agosto a las 8 de la mañana acude el transporte y montaje para terminar la cocina"

5 de agosto

  • Por la tarde nos llama por teléfono Yolanda Villar del servicio de atención al cliente de Ikea para comunicarnos que el lunes 8 no van a poder montar la cocina, que tendrá que ser el miércoles 10.

Mañana es miércoles. A las 9h estaremos en casa. ¿Qué pasará?.

¡¡ Increíble pero cierto!!: mientras escribo este post llega un SMS avisando que el montaje no va a poder ser mañana....  Dejo el post a medio escribir y salgo ahora (las 17h del 9 de agosto) hacia la tienda de Ikea. Luego vuelvo....

...

Ya estoy de vuelta: Nada que hacer. Me han atendido Ana Cristina y su supervisora Raquel. Han estado una hora haciendo gestiones y llamadas por teléfono tras las que me han confirmado que mañana no montarán la cocina. Que será pasado. 

No sé si pasado mañana, 11 de agosto será el capítulo final, o sólo uno más de la serie. El vaso está ya más que colmado y no tiene sentido alargar más este post que ya ha confirmado con creces el su titular: es el primer proyecto de mi vida que no soy capaz de gestionar, y la peor experiencia de usuario.

...

Apéndice

Por el interés que he despertado entre amigos y conocidos, y no dejar en suspense esta historia:

Hoy es 12 de agosto.

La promesa de terminar la cocina el día 11 no se ha cumplido. Algunas de las piezas que han traído (3 puertas creo) están confundidas y las tienen que volver a traer. A las 9 de la noche de ayer, hora a la que se iba el montador de casa me dijo que me avisarán de Ikea de cuándo las pueden traer y montar... Con gran esfuerzo voy a cumplir el propósito de contar esto con objetividad, y me reprimo las ganas de contar situaciones, comentarios y respuestas de las personas de atención al cliente y de los montadores de ikea, que parece imposible que puedan ser de la mayor empresa de muebles del mundo.

prometo avisar aquí el mismo día que Ikea tenga a bien dar fin a esta pesadilla. Mientras tanto.... es que sigo con esta vergonzante afrenta :-(

¡Terminado! :-)

Hoy, 17 de agosto, tras unas gestiones ayer en atención al cliente de Zaragoza y creo que gracias a la eficiencia de Pilar y Raquel, han terminado la instalación (en realidad queda un ajuste de la campana extractora, pero ya hemos quedado que en cuanto esté una pieza cortada la pondrán).

Así que doy por terminado el calvario :-)

Mi agradecimiento al personal de atención al cliente de Zaragoza, y el reproche al servicio de atención telefónica y a la empresa de transporte y montaje.

» Leer más, comentarios, etc...

Ingenieria de Software / Software Engineering / Project Management / Business Process Management

Tech Tools

August 09, 2016 01:14 PM

The SurePayroll Small Business Scorecard(R): Business Owners Rank Top Tech Tools for 2016 http://flip.it/NWxSq

» Leer más, comentarios, etc...

Ingenieria de Software / Software Engineering / Project Management / Business Process Management

BI | Power BI

August 09, 2016 01:12 AM

http://www.c-sharpcorner.com/article/reports-and-datasets-on-microsoft-power-bi/

» Leer más, comentarios, etc...

Poesía Binaria

7 Tareas comunes que echamos de menos en SQLite si venimos de otra base de datos SQL.

August 08, 2016 11:36 AM

5577388841_c86d1b41c2_o

Si en nuestra aplicación utilizamos una base de datos SQLite pero no estamos muy familiarizamos con la forma de trabajar de este pequeño motor, esta es tu guía. Aunque SQL es el mismo para muchas bases de datos (sobre todo las que tienen estas tres letras en su nombre: MSSQL, MySQL, PostgreSQL…), siempre hay unas pequeñas diferencias.
Esto no es una guía completa de SQLite, sólo una pequeña chuleta para algunas tareas comunes que pueden traernos de cabeza. Para los ejemplos, he utilizado algunas bases de datos SQLite de Firefox. Aunque otros programas como Skype, Dropbox, Thunderbird, muchísimos programas de Android… también usan SQLite.

Saber las tablas de una base de datos

Si estamos en el cliente SQLite oficial podemos escribir:

.tables
moz_anno_attributes  moz_favicons         moz_items_annos
moz_annos            moz_historyvisits    moz_keywords
moz_bookmarks        moz_hosts            moz_places
moz_bookmarks_roots  moz_inputhistory

Aunque si estamos programando una aplicación, debemos utilizar otra consulta:
SELECT name FROM sqlite_master WHERE type=’table';
moz_places
moz_historyvisits
moz_inputhistory
moz_hosts
moz_bookmarks
moz_bookmarks_roots
moz_keywords
sqlite_sequence
moz_favicons
moz_anno_attributes
moz_annos
moz_items_annos
sqlite_stat1

Describir una tabla

O saber cómo está formada, qué campos tiene, qué tipos de datos maneja… para SQLite. Cuando queremos hacer una petición a una tabla en este sistema y debemos saber cómo se llaman los campos que queremos pedir. Podemos hacer en el cliente de SQLite:

.schema moz_places
CREATE TABLE moz_places (   id INTEGER PRIMARY KEY, url LONGVARCHAR, title LONGVARCHAR, rev_host LONGVARCHAR, visit_count INTEGER DEFAULT 0, hidden INTEGER DEFAULT 0 NOT NULL, typed INTEGER DEFAULT 0 NOT NULL, favicon_id INTEGER, frecency INTEGER DEFAULT -1 NOT NULL, last_visit_date INTEGER , guid TEXT, foreign_count INTEGER DEFAULT 0 NOT NULL);
CREATE INDEX moz_places_faviconindex ON moz_places (favicon_id);
CREATE INDEX moz_places_hostindex ON moz_places (rev_host);
CREATE INDEX moz_places_visitcount ON moz_places (visit_count);
CREATE INDEX moz_places_frecencyindex ON moz_places (frecency);
CREATE INDEX moz_places_lastvisitdateindex ON moz_places (last_visit_date);
CREATE UNIQUE INDEX moz_places_url_uniqueindex ON moz_places (url);
CREATE UNIQUE INDEX moz_places_guid_uniqueindex ON moz_places (guid);

Incluso lo podemos hacer con la tabla sqlite_master (la que tiene información sobre las tablas):
.schema sqlite_master
CREATE TABLE sqlite_master (
type text,
name text,
tbl_name text,
rootpage integer,
sql text
);

Otras formas de pedir esta información pueden ser:

PRAGMA table_info(moz_places);
0|id|INTEGER|0||1
1|url|LONGVARCHAR|0||0
2|title|LONGVARCHAR|0||0
3|rev_host|LONGVARCHAR|0||0
4|visit_count|INTEGER|0|0|0
5|hidden|INTEGER|1|0|0
6|typed|INTEGER|1|0|0
7|favicon_id|INTEGER|0||0
8|frecency|INTEGER|1|-1|0
9|last_visit_date|INTEGER|0||0
10|guid|TEXT|0||0
11|foreign_count|INTEGER|1|0|0

Devolviéndonos un elemento por fila con los datos (ID de Columna, nombre, tipo, si puede ser NULL, valor por defecto, y si es clave primaria.

También podemos hacer otra cosa:

SELECT sql FROM sqlite_master WHERE name=’moz_places';
CREATE TABLE moz_places (   id INTEGER PRIMARY KEY, url LONGVARCHAR, title LONGVARCHAR, rev_host LONGVARCHAR, visit_count INTEGER DEFAULT 0, hidden INTEGER DEFAULT 0 NOT NULL, typed INTEGER DEFAULT 0 NOT NULL, favicon_id INTEGER, frecency INTEGER DEFAULT -1 NOT NULL, last_visit_date INTEGER , guid TEXT, foreign_count INTEGER DEFAULT 0 NOT NULL)

Conocer el último ID insertado

En SQLite, a no ser que se diga lo contrario, siempre tendremos un ID de fila para cada una de las filas que insertemos en cada tabla. Este Id de fila (o ROWID) no es visible si hacemos un SELECT * FROM tabla, aunque si podríamos hacer un SELECT rowid,* FROM tabla. Este ID identifica de forma unívoca una fila dentro de una tabla. Así evitamos tener que hacerlo nosotros, por ejemplo. En muchos sistemas de base de datos, podemos obtener el último ID insertado en una tabla, y aquí también. Si por ejemplo en una tabla hacemos:

INSERT INTO mitabla VALUES(43, 12, ‘Dato de ejemplo’);
SELECT last_insert_rowid();
4

Si queremos probarlo con el SELECT de antes sobre la misma tabla, veremos que el último dato tiene un ROWID 4.

NOW() fecha y hora actual

Si queremos plasmar la fecha actual en un campo de la base de datos, en muchos sistemas de base de datos SQL encontramos la función NOW(), aunque no en SQLite. Pero tenemos otra forma de sacar ese mismo dato:

SELECT date(‘now’)
2016-08-08
SELECT datetime(‘now’);
2016-08-08 10:24:04
SELECT time(‘now’);
10:24:32

Aunque también tenemos algunas posibilidades muy chulas como por ejemplo utilizar strftime() para dar la fecha en el formato que queramos, o la posibilidad de hacer operaciones con la fecha, como se indica a continuación:

SELECT strftime(‘%H:%M %d/%m/%Y (%s)’, ‘now’, ‘localtime’);
12:27 08/08/2016 (1470659251)
SELECT datetime(‘now’, ‘+1 month’);
2016-09-08 10:30:20
SELECT datetime(‘now’, ‘+1 month’, ‘+5 days’, ‘-3 hours’);
2016-09-13 07:31:50

Permitiéndonos muchas posibilidades. Por cierto, date(), datetime() y time() llaman internamente a strftime() por lo que strftime() puede ser utilizada con todos los modificadores que queramos.

Formateando la salida del SELECT

El cliente de SQLite permite obtener la salida formateada de diferentes maneras. Y eso es muy útil si utilizamos SQLite en nuestros scripts.

.mode column
SELECT id, url, guid FROM moz_places LIMIT 5;
1           http://www.mozilla.com/en-US/firefox/central/  nudGvVlQ89nh
2           http://www.ubuntu.com/                         caldnkjR-PGQ
3           http://wiki.ubuntu.com/                        LMwsRxTf2nMp
4           https://answers.launchpad.net/ubuntu/+addques  uX46uNYpYg4k
5           http://www.debian.org/                         AiVsuHkboUwM
.headers on
SELECT id, url, guid FROM moz_places LIMIT 1;
id          url                                            guid
----------  ---------------------------------------------  ------------
1           http://www.mozilla.com/en-US/firefox/central/  nudGvVlQ89nh
.mode csv
SELECT * FROM moz_hosts LIMIT 4;
id,host,frecency,typed,prefix
1,mozilla.com,140,0,
2,ubuntu.com,140,0,
3,wiki.ubuntu.com,140,0,
4,answers.launchpad.net,128,0,

Y muchos modos más si utilizamos .help

Obtener la versión con una consulta

Aunque tanto desde su interfaz C como desde el cliente, podemos obtener la versión de SQLite, puede que alguna vez necesitemos una consulta para ello, o para obtener esta versión junto con más cosas. Podemos hacerlo así:

SELECT sqlite_version();
3.8.6

Formatear columnas

¿Y si, formateamos columnas como si estuviéramos programando en C? A partir de SQLite 3.8.3 (2014) podemos utilizar la función printf() en nuestras consultas y hacer cosas tan chulas como:

SELECT printf(‘%s-%.2d-%.4d’, host, frecency, typed) AS out FROM moz_hosts LIMIT 4;
out
--------------------
mozilla.org-100-0000
ubuntu.com-2075-0001
wiki.ubuntu.com-100-
answers.launchpad.ne
SELECT printf(‘%05d’, 123);
00123
SELECT printf (‘%09.4f’, 43.23);
0043.2300
SELECT printf (‘%X’, 12380);
305C

Y esto tiene muchas más posibilidades que un CONCAT().

Foto Principal: Chris Dlugosz

The post 7 Tareas comunes que echamos de menos en SQLite si venimos de otra base de datos SQL. appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Blog Bitix

Cómo y por que redirigir tráfico web del dominio raíz al subdominio www (o viceversa)

August 05, 2016 04:00 PM

La redirección del dominio raíz al subdominio es una de las cosas básicas que es recomendable realizar en todo dominio, para ello hay que añadir algo de configuración propia de cada servidor para realizar la redirección. Junto con usar el uso del protocolo HTTPS y forzar su uso con otra redirección mejoraremos el SEO y evitaremos penalizaciones por contenido duplicado.

HTML

El nombre de un dominio está formado por varios subdominios separados por un caracter punto. Están los dominios de nivel superior, los genéricos y más antiguos .com, .org, .info, .net, los propios de cada país o territoriales .es, .fr, .de y más recientemente un montón de nuevos dominios de nivel superior (.futbol, .arte, .blog, .madrid, …) aunque significativamente más caros. Después del dominio de nivel superior está el subdominio de la empresa, marca o personal, por ejemplo, empresa.com que es realmente lo que compramos cuando solicitamos registrar un dominio. En nuestro dominio empresa.com podemos administrar múltiples subdominios los clásicos son www.empresa.com para el servidor web, smpt.empresa.com para el correo electrónico, ftp.empresa.com para la transferencia de archivos y otros cualesquiera que deseemos.

En el caso del tráfico web debemos evitar que el servidor y la página o aplicación sea accedida por empresa.com y www.empresa.com ya que los buscadores tratarán a la página como dos diferentes y posiblemente detectando contenido duplicado que afectará negativamente o penalizando al SEO de la web. Lo que se suele hacer es hacer una redirección permanente (cuyo código de estado HTTP para la respuesta es 301) a nivel de servidor que redirija el tráfico de empresa.com a www.empresa.com cuando el usuario acceda con su navegador con la primera.

Esta es una de las cosas básicas que debemos realizar cuando instalemos un servidor web, otras cosas recomendadas para mejorar el SEO y la seguridad de los usuarios es configurar el servidor web para usar el protocolo seguro HTTPS y configurar el servidor web para forzar el uso de HTTPS también haciendo una redirección cuando la petición use el protocolo no cifrado HTTP entre otras cosas que indico en la serie web.

Dependiendo del servidor web que utilicemos la configuración a añadir para hacer la redirección será distinta, a continuación indicaré como hacerlo en dos de los servidores web más populares como son Nginx y Apache HTTPD.

Nginx

Usando Docker y el archivo de configuración completo podemos probar que funciona en local sin necesidad de instalar o cambiar la configuración de Nginx si tenemos instalado su paquete.

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/82d3c361c947d57a25b346b386bdf3a9/raw/docker-run-nginx.sh">docker-run-nginx.sh</pre></a></noscript>
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/82d3c361c947d57a25b346b386bdf3a9/raw/nginx.conf">nginx.conf</pre></a></noscript>
Dominio antes y después de acceder al sitio con Nginx

Apache

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/82d3c361c947d57a25b346b386bdf3a9/raw/docker-run-httpd.sh">docker-run-httpd.sh</pre></a></noscript>
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/82d3c361c947d57a25b346b386bdf3a9/raw/httpd.conf">httpd.conf</pre></a></noscript>
Dominio antes y después de acceder al sitio con Apache HTTPD

Si prefieriesemos hacer la redirección al revés, del subdominio www al dominio, variaríamos los valores de los nombres del servidor y los valores de las directivas de redirección. En los enlaces de referencia se incluye un ejemplo de esta configuración.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub.

Referencia:

» Leer más, comentarios, etc...

Adrianistán

ShortKin.gq, un acortador de enlaces anónimo

August 04, 2016 04:55 PM

ShortKin.gq es un proyecto en el que he trabajado solamente dos días, sin embargo, creo que ya puede ser de utilidad. Se trata de un acortador de enlaces, gratuito y anónimo. Los enlaces durán para siempre pero nadie sabe quien los creó. El servicio no dispone de anuncios, por lo que puedes estar tranquilo y usarlo donde te apetezca, no será baneado de foros y redes sociales. Actualmente usa Heroku

ShortKing

Bonus: API pública

Puedes usar ShortKin.gq en tu propio proyecto a través de una API muy sencilla. Simplemente has de llamar a:

http://shortkin.gq/s?url=URL

Y se te devolverá el enlace acortado. Muy fácil de usar en tus aplicaciones.

La entrada ShortKin.gq, un acortador de enlaces anónimo aparece primero en Blog - Adrianistan.eu.

» Leer más, comentarios, etc...

Poesía Binaria

Demuestra tu destreza con la terminal desde tu blog

August 04, 2016 12:43 PM

Screenshot 04-08-2016-140814Hace unos días liberé una primera versión de SimTerm, y será de las pocas veces que utilice este blog para dar noticias sobre el proyecto (para eso estará en breve la web del proyecto).
Durante esta semana he introducido algunas mejoras interesantes:

  • Corrección de signos — y — de WordPress que transformará en ‐‐ y ‐‐‐ ya que en la línea de comandos, esto se usa muchísimo y en este blog me he peleado muchísimo con estos símbolos
  • Corrección de espacios, para representar una tabla en terminal viene muy bien.
  • Cambio del título de la ventana, porque queda muy chulo. Hasta se puede cambiar desde el shortcode
  • Cambio automático de retardos en función de la posición del texto. Sin tener que hacer nada el plugin detecta las líneas normales, la última línea y cuando hay varias líneas de salida juntas adaptando los retardos automáticamente. Aunque podemos cambiar los retrasos cuando queramos manualmente.
  • La velocidad de tecleo también se puede cambiar, tanto en la configuración del plugin como en una línea en cuestión.
  • Se añade soporte para traducciones. Así cualquiera puede adaptarlo a su idioma. Ahora mismo sólo está en español y en inglés.
  • Colaboro en la ampliación del script original para añadir nuevas características como múltiples ventanas con animación y posibilidad de pausar y reanudar las animaciones.

Formas de instalar el plugin

Desde hace dos días, podemos encontrar el plugin también en wordpress.org; me ha sorprendido la prisa que se han dado para dejarme publicar el plugin en la web, dado que cuando lo envié había unos 130 en lista de espera. Para instalar el plugin, puedes hacerlo de varias formas:

  • Desde la propia administración de plugins WordPress, buscando simterm.Screenshot 04-08-2016-120848, e instalándolo desde ahí.
  • Descargándolo desde https://wordpress.org/plugins/simterm/ (que es casi casi lo mismo que antes) y luego descomprimiendo y copiando los archivos a wp-content/plugins/
  • Descargándolo desde GitHub y copiándolo en el mismo lugar que antes.

Ayudar con el proyecto

El proyecto es 100% libre. Y como con cualquier programa, estoy abierto a colaboraciones y ayuda de cualquier tipo:

  • Instalar el plugin en tu WordPress y empezar a usarlo. Es el objetivo de cualquier programa. Sé que no es algo que quieran todos los editores de WordPress, pero seguro que a más de uno le puede interesar.
  • Compartir esta información para que el plugin se conozca y se use.
  • Reportar errores que encontréis y comunicarme futuras mejoras. Por cualquier medio, desde aquí, desde WordPress, desde GitHub, o desde Twitter o Facebook si lo preferís.
  • Colaborar con las traducciones. Podéis traducir generar los archivos PO y MO, o utilizar el propio sistema de WordPress para traducciones.
  • Colaborar con código. Podéis hacer fork desde github, que sería lo más cómodo, pero si me envías los archivos por correo también lo acepto.
  • Si queréis colaborar con las imágenes (sé que no son muy buenas), podéis contactar conmigo y enviármelas, os lo agradeceré eternamente.
  • Siempre se agradece un voto en la web de WordPress.org por ejemplo.

Alguna demostración más

mysql -uroot -p[PASSWORD]
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 1106
Server version: 5.1.65-log MySQL Community Server (GPL)
USE poebin;
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
SELECT * FROM prose_terms LIMIT 10;
+---------+---------------+---------------+------------+
| term_id | name          | slug          | term_group |
+---------+---------------+---------------+------------+
|       1 | Uncategorized | uncategorized |          0 |
|       2 | Blogroll      | blogroll      |          0 |
|       3 | hello         | hello         |          0 |
|       4 | world         | world         |          0 |
|       5 | first         | first         |          0 |
|       6 | program       | program       |          0 |
|       7 | start         | start         |          0 |
|       8 | writing       | writing       |          0 |
|       9 | code          | code          |          0 |
|      10 | languages     | languages     |          0 |
+---------+---------------+---------------+------------+
10 rows in set (0.00 sec)

Otra demostración

openssl genrsa -rand <(arecord -d5 -c1 -r 8000 | lame -S -x -h -b 32 -) -out privadax.key 4096
Grabación WAVE 'stdin' : Unsigned 8 bit, Ratio 8000 Hz, Mono
LAME 3.99.5 64bits (http://lame.sf.net)
polyphase lowpass filter disabled
Encoding  to
Encoding as 8 kHz single-ch MPEG-2.5 Layer III (4x)  32 kbps qval=2
20736 semi-random bytes loaded
Generating RSA private key, 4096 bit long modulus
………………………++
…………………………………++
e is 65537 (0x10001)

Pronto el “making of”…

Y en unos días empezaré a publicar el making of des este plugin en varias partes, pensado para todos aquellos que queráis empezar a programar un plugin para WordPress.

The post Demuestra tu destreza con la terminal desde tu blog appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Poesía Binaria

Cómo saber si existe una función en Bash, saber qué estamos ejecutando y más

August 01, 2016 08:36 AM

photo-1457317680121-ef12e98979e8

En nuestra historia como programadores, hacemos infinidad de llamadas a funciones propias, de terceros, de biblioteca, a otros programas a un alias, etc Y si queremos que nuestros scripts sean lo más robustos posible, debemos tener claro antes de la ejecución que aquello que llamamos se puede ejecutar o dar opciones si algún comando o función no existe.

Por ejemplo, nuestro script necesita hacer una llamada a wget de este tipo:

wget -O salida http://totaki.com

Pero queremos hacer que sea compatible con otros sistemas, por ejemplo, con cURL, y no podemos cambiar uno por otro, pues con curl sería con o minúscula:

curl -o salida http://totaki.com

Nuestro script podrá ser:

1
2
3
4
5
6
7
8
if [ -n "$(which wget)" ]; then
    wget -O salida http://totaki.com
elif [ -n "$(which curl)" ]; then
    curl -o salida http://totaki.com
else
    echo "No puedo descargar el fichero"
    exit 1
fi

De modo que probamos la existencia de diferentes programas y utilizamos el que tengamos a disposición. Otra forma sería crear una función bash que se llame wget, pero que utilice cURL para trabajar:

1
2
3
4
5
6
7
8
if [ -z "$(which wget)" ]; then
   function wget()
   {
      curl -o "$2" "$3"
   }
fi

wget -O salida http://totaki.com/

Aunque sólo funcionará cuando las llamadas a wget sean siempre de la misma forma. Ahora bien, hemos utilizado which para conocer dónde se ubica el archivo ejecutable de dicho comando, pero, ¿ y si el comando que estamos utilizando es un alias, o una función de bash ? en ese caso which serviría de poco, ya que éste suele ser un programa externo (en casi todos los Unix), y siendo un programa externo no podría acceder fácilmente a objetos almacenados en Bash.

Para ello, Bash proporciona una orden interna llamada type, que es capaz de decirnos de qué se trata el comando que le pasamos como argumento. Por ejemplo:

$ type wget
wget is /usr/bin/wget
$ type sudo
sudo is /usr/bin/sudo
$ type for
for es una palabra clave del shell
$ function funci() { echo “Hello World!”; }
$ type funci
funci: es una función
funci ()
{
echo “Hello World!”
}
$ type time
time es una palabra clave del shell
$ type echo
echo es una orden interna del shell
$ type ls
ls es un alias de `ls –color=auto’
$ type type
type es una orden interna del shell
$ type algoquenoexiste
bash: type: algoquenoexiste: no se encontró

Estos son algunos ejemplos. Como curiosidad, tenemos time, que es palabra clave de shell, interno de Bash, aunque también existe un comando time que debe ser llamado explícitamente /usr/bin/time; si sólo llamamos a time, Bash prefiere llamar primero a la versión interna, le pilla más cerca.
Vemos también que palabras como for, if, while, case, do, etc también son detectadas por type. Es más, type, se autodefine como orden interna.
Por otro lado, en distribuciones como Ubuntu y derivadas, encontramos que ls es un alias de ls –color=auto para que todo se vea un poco más bonito

¿cómo utilizar esto en nuestros scripts

Pero, ¿cómo utilizamos esto en nuestros scripts? La salida de type es algo compleja para tener que analizarla con métodos textuales, y como vemos, está en español, por lo que estará traducida a decenas de idiomas y eso no es bueno a la hora de llevarnos los scripts a otros lugares. Afortunadamente, type tiene un modificador, -t, que nos devuelve palabras sencillas en inglés (sea cual sea el idioma que utilicemos) que sí podremos utilizar en nuestros scripts:

$ type -t wget
file
$ type -t sudo
file
$ type -t for
keyword
$ type -t funci
function
$ type -t time
keyword
$ type -t echo
builtin
$ type -t ls
alias
$ type -t type
builtin
$ type -t algoquenoexiste

Vemos que en el último caso no recibimos respuesta, es decir, está vacía.

Y con este modificador podremos hacer algo como:

1
2
3
if [ -n "$(type wget)" ]; then
  echo "Existe wget, ya sea aplicación, alias, función..."
fi

Porque si no tenemos wget instalado, tenemos la función anterior creada y utilizamos which, éste seguirá dando un negativo.

Aunque también podemos, como dice el título, verificar la existencia de funciones, algo así como un typeof de Javascript:

1
2
3
if [ "$(type mifuncion)" = "function" ]; then
   echo "La función existe";
fi

o

1
2
3
if [ -z "$(type mifuncion)" ]; then
   echo "La función NO existe";
fi

Y esto podríamos utilizarlo cuando incluimos scripts, a modo de plugin de nuestro script:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
for plugin in plugins/*.sh; do
  \. $plugin
  plugin_name=${plugin%.*}

  if [ -z "$(type $plugin_name"_version")" ]; then
    echo "Plugin $plugin_name no válido"
    exit 1
  fi

  if [ "$(type $plugin_name"_init")" = "function" ]; then
    echo "Inicializando plugin $plugin_name"
    $plugin_name"_init"
  fi
done

Con este pequeño script incorporaríamos todos los archivos .sh que estén dentro del directorio plugins, tras ello, buscaríamos las funciones cuyos nombres son: “nombre_del_archivo_version” y “nombre_del_archivo_init”. Los nombres del archivo van sin extensión. La primera función, si no la encontramos, concluiremos el programa diciendo que el plugin no es válido; la segunda hará una ejecución a dicha función si existe, porque el plugin tal vez no tenga que ser inicializado.

Foto: Matthew Kane

The post Cómo saber si existe una función en Bash, saber qué estamos ejecutando y más appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Blog Bitix

Configurar Nginx para cachear respuestas del servidor de aplicaciones

July 30, 2016 11:00 PM

Las caches son un recurso utilizado para aumentar el rendimiento y evitar malgastar recursos. Si una petición es muy costosa pero que no cambia muy a menudo o no se necesitan que los datos estén totalmente actualizados cachear el resultado de esa petición evitará tener que recalcularla para cada petición, si se realizan muchas peticiones el aumento de rendimiento será drásticamente mejor usando además un menor número de recursos de los sistemas. Hay soluciones específicas para cacheo pero si nuestra necesidades no son extremadamente avanzadas el cacheo ofrecido por Nginx probablemente sea suficiente.

Nginx

Los servidores web son muy eficientes devolviendo al cliente archivos estáticos. Tradicionalmente el contenido estático formado por hojas de estilo, archivos JavaScript, imágenes o vídeos de una página o aplicación web han sido devueltos por un servidor web evitando que el servidor de aplicaciones tenga que procesar una gran cantidad de peticiones, aún hoy se sigue haciendo. En caso de que los recursos estáticos estén alojados en el servidor de aplicaciones en vez de en el servidor web, porque los recursos estáticos se empaquetan con la aplicación, el servidor web puede cachearlos evitando que peticiones lleguen al servidor de aplicaciones. En este artículo comentaré cual es la configuración necesaria a añadir en el servidor web Nginx que hace de proxy para que cachee el resultado de las peticiones así indicadas del servidor de aplicaciones, la aplicación genera el contenido y establece las cabeceras de cache indicando como quiere que se cachee el contenido devuelto.

Para que el servidor web realice el cacheo de los recursos en la aplicación esta ha de devolver en las cabeceras de respuesta como quiere que los recursos sean cacheados usando las cabeceras Last-Modified, Expires, Cache-Control quizá Etag. Las cabeceras de cache del protocolo HTTP establecen el comportamiento deseado para la cache.

Hay que modificar el archivo de configuración de Nginx para que cachee el contenido. La directiva proxy_cache_path indica donde se guardarán el contenido cacheado, cual es el tamaño de los metadatos de la caché y el tiempo de inactividad para cachear pasado el cual los recursos serán descartables. La directiva proxy_cache_key permite diferenciar los recursos en la cache, add_header X-Proxy-Cache añade una cabecera para la respuesta de Nginx con el resultado de cache que nos permite conocer si se produjo un acierto en la caché, un fallo o se ignoró la cache. Lo que es útil para depurar la aplicación u obtener información. Con proxy_pass hacemos que Nginx haga de proxy para el servidor de aplicaciones o la aplicación.

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/9bc353ad2c84bfd320c4819f2a91b98c/raw/nginx.conf">nginx.conf</pre></a></noscript>
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/9bc353ad2c84bfd320c4819f2a91b98c/raw/docker-compose.yml">docker-compose.yml</pre></a></noscript>

La siguiente pequeña aplicación Java que usa el framework Spark expone dos recursos para probar el funcionamiento de cache de Nginx, un recurso añade cabeceras de cacheo para la respuesta y otro no añade las cabeceras de respuesta. Atendiendo a las cabeceras establecidas por la aplicación y Nginx configurado para hacer de proxy y cache devolverá el contenido deseado de su cache o solicitándolo a la aplicación y cacheándolo si así se indica en las cabeceras de respuesta.

<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/9bc353ad2c84bfd320c4819f2a91b98c/raw/Main.java">Main.java</pre></a></noscript>

La primera petición que se realiza al recurso cache devuelve un código de estado 200 de HTTP y Nginx en la cabecera X-Proxy-Cache indica que se ha producido un MISS o fallo en la cache, la segunda petición realizada antes de que pase el minuto del tiempo de expiración devuelve un código de estado 304 y Nginx en la cabecera X-Proxy-Cache un HIT o acierto en la cache, finalmente pasado más de un minuto del tiempo de expiración se devuelve un código de estado 200 y Nginx en la cabecera X-Proxy-Cache un EXPIRED. En las trazas de Nginx vemos las peticiones que se producen sus códigos de estado y después de este los bytes transferidos de contenido, nótese que en los casos de los 304 los bytes transferidos son 0, bytes de datos ahorrados y evitado que la petición llegue a la aplicación que son unos de los objetivos de las caches. En el recurso nocache de la aplicación Nginx no cachea el contenido devuelto ya que en este no se establecen las cabeceras de cache en la respuesta.

Fallo, acierto y expiración que produce en la cache de Nginx al realizar peticiones
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/9bc353ad2c84bfd320c4819f2a91b98c/raw/nginx.out">nginx.out</pre></a></noscript>
<noscript><pre><a href="https://gist.githubusercontent.com/picodotdev/9bc353ad2c84bfd320c4819f2a91b98c/raw/curl-cache.sh">curl-cache.sh</pre></a></noscript>

Hay servidores específicos para realizar tareas de cache como Varnish con más opciones de las que ofrece Nginx. Para los casos no complicados usando Nginx evitamos añadir una nueva pieza a la arquitectura de la aplicación. Entre los productos que ofrece Amazon está Cloudfront que es una cache para recursos estáticos con el añadido de que de forma automática está distribuida geográficamente de forma que los recursos se sirven por un servidor más cercano al cliente evitando un mal rendimiento por la latencia. En el artículo servir recursos estáticos de un CDN en Apache Tapestry comento como usar esta red de distribución de contenido ofrecida por Amazon.

El código fuente completo del ejemplo puedes descargarlo del repositorio de ejemplos de Blog Bitix alojado en GitHub y probarlo en tu equipo ejecutando el comando ./gradlew build && cd docker && docker-compose up.

» Leer más, comentarios, etc...

.NET o no .NET, esa es la cuestión

Adiós Embarcadero, adiós

July 30, 2016 02:36 PM

No es muy conocido que yo he trabajado en la filial española de la empresa Embarcadero, dueña de Delphi y C++ Builder, dos productos que fueron lo más pero que ya no lo son, opinión personal, por supuesto.

Yo dejé la empresa para irme a trabajar a Holanda, y no me arrepiento. El mismo día en el que dije que me iba, nos comunicaron que Idera, una pequeña empresa de bases de datos, había comprado a Embarcadero. Tan solo hubo dos horas entre el momento en que oficialmente pedí la baja voluntaria y el que anunciaron la compra. Para nosotros fue como si un lenguado se hubiera comido una ballena, porque aparentemente Idera era una empresa chiquita comiéndose a una empresa mucho mayor, pero claro, detrás están los grupos de inversión que son los que realmente hacen estas operaciones.

Personalmente he vivido dos compras de este tipo trabajando en empresas grandes, y ninguna fue traumática en exceso para los empleados como yo. Me refiero a que, pese al cambio de jefes, a los currantes poco nos cambió la cosa si no es algún que otro cambio en las reglas de funcionamiento interno…

Pero aquí parece que la cosa se presenta mucho más diferente. Básicamente, parece ser que Idera está echando a la calle a todas las divisiones de Embarcadero en todo el mundo. Un recorte a lo Microsoft, pero mucho más drástico. Al menos es lo que se deja entrever en la entrada del amigo José León, jefazo de la filial española y que él mismo cuenta cómo llegó a serlo.

Para que os hagáis una idea, Embarcadero ha mantenido a lo largo de todo el mundo “pequeños” grupos de trabajo, encargados de distintas partes de sus productos. Sin ir más lejos, en la filial de Elche, una de las que cierran y en la que yo estuve trabajando, se hace parte del producto de Delphi, C++ Builder y DbPower Studio, que era donde yo estaba. Había más grupos, si no recuerdo mal, en Polonia, Rusia…

Parece ser que todos esos grupos están siendo cerrados a golpe de ERE. Lo que es triste, aunque también es algo que se veía venir dado el devenir de Embarcadero porque, por ejemplo, o abandoné C++ Builder asqueado de los bugs y problemas que presentaba, aparte de las restricciones en la activación del producto…

También parece ser que yo dejé de usarlo justo cuando empezó a desarrollarse en España, y por lo que he visto desde dentro, la calidad ha mejorado sensiblemente, pero parece ser que no justifica dos versiones por año que ponen el precio de la herramienta por encima de las posibilidades del usuario medio, máxime cuando en estos momentos Visual Sutdio + Xamarin son gratuitos para ese mismo tipo de usuario.

Tampoco es que Xamarin sea la panacea, las pocas veces que lo he usado he terminado hasta los cojones del producto por su baja calidad, pero es una alternativa al mismo nivel de sencillez que Delphi, así que no llueven buenos tiempos para estos productos, porque si cierran los centros de desarrollo… ¿quién va a continuar con las nuevas versiones?

¿Se van a hacer en Estados Unidos, a 100K/año el desarrollador cuando en España está a cuatro veces menos? ¿Van a contratar de nuevo a Helsberg? ¿Nos ha engañado José León y resulta que no es un súper-developer, sino que es el mayor genio que ha parido madre y va a seguir él solo con el producto? ¿Ha inventado alguien una IA programadora capaz de construir todo eso sin necesidad de personas?

No, lo que creo, tristemente, es que Delphi, C++Builder y quizás los productos de bases de datos se van al garete, sustituidos por los de Idera, que os aseguro no le llegan a la suela de los zapatos.

En fin, es lo que hay. El VHS le ganó al 2000 y al Beta, y no por ser mejor producto o tecnología.

RIP, Delphi.

RIP, C++ Builder.

» Leer más, comentarios, etc...

Poesía Binaria

Un plugin de WordPress para hacer demostraciones animadas de comandos de terminal: simterm

July 29, 2016 08:29 AM

terminales¿Harto de que ponga todas mis andanzas en terminal de Linux de forma muy pobre y sin color? ¿Que casi no se distingue la entrada de datos de la respuesta de los programas? Y eso que intento que quede todo claro, pero en ocasiones no es fácil de conseguir, y con la cantidad de ejemplos que pongo por aquí no es sostenible tener que editarlos todo el rato para que queden bien en HTML.

Bueno, todo eso se acabó. Acabo de subir una primera versión de este plugin: simterm. Más o menos, simulador de terminal, y es que dibuja una ventana allá donde queramos y simula una entrada de datos y una salida con un look and feel mucho mejor. Aquí tenéis un ejemplo:

ls
css  mutils.php        simterm-line.php      views
img  readme.txt        simterm.php           views.php
js   simterm-core.php  simterm-settings.php
touch probando
ls -latr
total 64
drwxr-xr-x 2 gaspy gaspy 4096 jul 17 02:07 img
-rw-r--r-- 1 gaspy gaspy    6 jul 17 02:34 mutils.php
-rw-r--r-- 1 gaspy gaspy 1866 jul 25 20:47 simterm-line.php
-rw-r--r-- 1 gaspy gaspy  951 jul 26 02:15 views.php
-rw-r--r-- 1 gaspy gaspy 1971 jul 26 02:18 simterm-core.php
drwxr-xr-x 2 gaspy gaspy 4096 jul 26 02:32 css
drwxr-xr-x 2 gaspy gaspy 4096 jul 26 02:32 js
drwxr-xr-x 4 gaspy gaspy 4096 jul 26 02:32 views
-rw-r--r-- 1 gaspy gaspy  300 jul 26 02:42 .gitignore
-rw-r--r-- 1 gaspy gaspy 1213 jul 26 02:59 readme.txt
drwxr-xr-x 4 gaspy gaspy 4096 jul 26 03:01 ..
-rw-r--r-- 1 gaspy gaspy 4285 jul 26 03:05 simterm-settings.php
-rw-r--r-- 1 gaspy gaspy  965 jul 26 20:37 simterm.php
drwxr-xr-x 8 gaspy gaspy 4096 jul 26 20:38 .git
-rw-r--r-- 1 gaspy gaspy    0 jul 27 01:26 probando
drwxr-xr-x 7 gaspy gaspy 4096 jul 27 01:26 .
rm probando

Y después de 7 años…

Sí, llevo 7 años con el blog y no se me había ocurrido nada parecido. Bueno, hace tiempo vi un plugin para esto, pero era un simple div con un css y un icono de terminal, pero creo que esto está más chulo. Y todo fue a raíz de ver que alguien a quien sigo en GitHub puso una estrella esto: Show Your Terms. A mí me encantó y busqué a ver si había algo parecido en WordPress. Yo tenía muchas ganas de empezar un plugin para WordPress desde cero (y crear un tutorial para el blog, que veréis en poco tiempo), así que aproveché este momento.

¿Cómo lo instalo en mi blog?

Si quieres utilizar SimTerm en tu blog, descárgate el plugin desde GitHub. Por el momento no está en el directorio de plugins oficiales, se encuentra en revisión y hay una larga cola de plugins por delante. Planeo habilitar una pequeña página con más información sobre el plugin, pero eso será a medida que vaya sacando tiempo.

Una vez descargado, descomprimelo dentro de wp-content/plugins, ve a la pantalla de plugins de tu instalación de WordPress y activa SimTerm.

Puedes configurar algunas cosas si entras en Ajustes > SimTerm Settings como el carácter que precede los comandos o la entrada de texto del usuario, así como el tema del terminal (claro, oscuro, regular o azul para la versión 0.10). Luego, dentro de tu post, simplemente escribe:

[simterm]
$ mysql
Welcome to the MySQL monitor. Commands end with ; or \g.
Your MySQL connection id is 454
Server version: 5.1.65-log MySQL Community Server (GPL)
> SELECT * FROM wp_options LIMIT 10,10;
+———–+————————+——————-+———-+
| option_id | option_name | option_value | autoload |
+———–+————————+——————-+———-+
| 11 | comments_notify | 1 | yes |
| 12 | posts_per_rss | 10 | yes |
| 13 | rss_use_excerpt | 0 | yes |
| 14 | mailserver_url | mail.example.com | yes |
| 15 | mailserver_login | login@example.com | yes |
| 16 | mailserver_pass | password | yes |
| 17 | mailserver_port | 110 | yes |
| 18 | default_category | 1 | yes |
| 19 | default_comment_status | open | yes |
| 20 | default_ping_status | open | yes |
+———–+————————+——————-+———-+
10 rows in set (0.00 sec)
> UPDATE wp_options SET option_value=100 WHERE option_name=’posts_per_rss';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1 Changed: 1 Warnings: 0
[/simterm]

Y esto se verá así:

mysql
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 454
Server version: 5.1.65-log MySQL Community Server (GPL)
SELECT * FROM wp_options LIMIT 10,10;
+-----------+------------------------+-------------------+----------+
| option_id | option_name            | option_value      | autoload |
+-----------+------------------------+-------------------+----------+
|        11 | comments_notify        | 1                 | yes      |
|        12 | posts_per_rss          | 10                | yes      |
|        13 | rss_use_excerpt        | 0                 | yes      |
|        14 | mailserver_url         | mail.example.com  | yes      |
|        15 | mailserver_login       | login@example.com | yes      |
|        16 | mailserver_pass        | password          | yes      |
|        17 | mailserver_port        | 110               | yes      |
|        18 | default_category       | 1                 | yes      |
|        19 | default_comment_status | open              | yes      |
|        20 | default_ping_status    | open              | yes      |
+-----------+------------------------+-------------------+----------+
10 rows in set (0.00 sec)
UPDATE wp_options SET option_value=100 WHERE option_name=’posts_per_rss';
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0

Configuración precisa para cada línea

Se puede configurar el color de escritura en cada línea utilizando comodines de la siguiente forma al principio de la línea:

##clave##

o

##clave=valor##

para los elementos que admiten configuración. Asimismo se pueden especificar varios comodines de la siguiente manera:

##clave1,clave1=valor2,clave2##

Por ejemplo podemos escribir esto:

[simterm]
##red##$ inserto un comando
##green,delay=2000##Espere un momento por favor…
##blue,delay=1000##Respuesta del comando
##yellow##$ read -n16 VARIABLE
##red##> inserto un texto
##yellow##$ comando -complicado –con “muchos argumentos”
##underline##Respuesta muy importante
##blink##Fin de la simulación
[/simterm]

Y obtener lo siguiente:

inserto un comando
Espere un momento por favor…
Respuesta del comando
read -n16 VARIABLE
inserto un texto
comando -complicado --con “muchos argumentos”
Respuesta muy importante

Documentación, más ejemplos y mucho más

Si quieres más información sobre este plugin ve a esta web. La iré rellenando poco a poco.

Colaborar con el plugin

Si quieres colaborar con el plugin aportando código, traducciones, solucionando problemas, etc, haz un fork en el GitHub del proyecto, trabaja en tu propio repositorio, sube los cambios y hazme un pull request. Si lo prefieres también puedes enviarme un mensaje o comentar algo, me pongo en contacto contigo y me envías los archivos, pero seguro que es más cómodo para todos de la otra forma.
Si quieres hacer sugerencias o informar de algún problema, puedes hacerlo a través de comentarios en este post, en la página de SimTerm, o en GitHub. Intento contestar todo en función del tiempo de que disponga.

The post Un plugin de WordPress para hacer demostraciones animadas de comandos de terminal: simterm appeared first on Poesía Binaria.

» Leer más, comentarios, etc...

Meta-Info

¿Que es?

Planeta Código es un agregador de weblogs sobre programación y desarrollo en castellano. Si eres lector te permite seguirlos de modo cómodo en esta misma página o mediante el fichero de subscripción.

rss subscripción

Sponsors

Puedes utilizar las siguientes imagenes para enlazar PlanetaCodigo:
planetacodigo

planetacodigo

Si tienes un weblog de programación y quieres ser añadido aquí, envíame un email solicitándolo.

Idea: Juanjo Navarro

Diseño: Albin