sábado, 2 de septiembre de 2017

Configurar Android Devices para desarrollo en Linux (Debian 8)

Es muy comun encontrarse este error despues de ejecutar:

adb devices

#Error al mostrar que no hay permisos:
List of devices attached
M4 SS1070       no permissions (verify udev rules); see [http://developer.android.com/tools/device.html]

Aquí el problema es que los usb son mas restrictivos en linux.
Pero no te alarmes. Es sencillo de resolver.

Lo que voy a mostrar en una recopilación de la mayoría de vendors para que no sufras mas por esto. Eventualmente si después de seguir los pasos abajo mostrados aun te sigue saliendo.
Tendrás que buscar el vendo-Id correcto para tu device.

#Edita/Agregar el archivo de udev rules
sudo nano /etc/udev/rules.d/51-android.rules

#Agregar la lista de abajo al archivo.#51-android.rules: 
#Lista con los vendors mas comunes
SUBSYSTEM=="usb", ATTR{idVendor}=="0502", MODE="0666", GROUP="plugdev" #Acer
SUBSYSTEM=="usb", ATTR{idVendor}=="0b05", MODE="0666", GROUP="plugdev" #ASUS
SUBSYSTEM=="usb", ATTR{idVendor}=="413c", MODE="0666", GROUP="plugdev" #Dell
SUBSYSTEM=="usb", ATTR{idVendor}=="0489", MODE="0666", GROUP="plugdev" #Foxconn
SUBSYSTEM=="usb", ATTR{idVendor}=="04c5", MODE="0666", GROUP="plugdev" #Fujitsu
SUBSYSTEM=="usb", ATTR{idVendor}=="04c5", MODE="0666", GROUP="plugdev" #Fujitsu Toshiba
SUBSYSTEM=="usb", ATTR{idVendor}=="091e", MODE="0666", GROUP="plugdev" #Garmin-Asus
SUBSYSTEM=="usb", ATTR{idVendor}=="18d1", MODE="0666", GROUP="plugdev" #Google
SUBSYSTEM=="usb", ATTR{idVendor}=="201E", MODE="0666", GROUP="plugdev" #Haier
SUBSYSTEM=="usb", ATTR{idVendor}=="109b", MODE="0666", GROUP="plugdev" #Hisense
SUBSYSTEM=="usb", ATTR{idVendor}=="0bb4", MODE="0666", GROUP="plugdev" #HTC
SUBSYSTEM=="usb", ATTR{idVendor}=="12d1", MODE="0666", GROUP="plugdev" #Huawei
SUBSYSTEM=="usb", ATTR{idVendor}=="24e3", MODE="0666", GROUP="plugdev" #K-Touch
SUBSYSTEM=="usb", ATTR{idVendor}=="2116", MODE="0666", GROUP="plugdev" #KT Tech
SUBSYSTEM=="usb", ATTR{idVendor}=="0482", MODE="0666", GROUP="plugdev" #Kyocera
SUBSYSTEM=="usb", ATTR{idVendor}=="17ef", MODE="0666", GROUP="plugdev" #Lenovo
SUBSYSTEM=="usb", ATTR{idVendor}=="1004", MODE="0666", GROUP="plugdev" #LG
SUBSYSTEM=="usb", ATTR{idVendor}=="22b8", MODE="0666", GROUP="plugdev" #Motorola
SUBSYSTEM=="usb", ATTR{idVendor}=="0e8d", MODE="0666", GROUP="plugdev" #MTK
SUBSYSTEM=="usb", ATTR{idVendor}=="0409", MODE="0666", GROUP="plugdev" #NEC
SUBSYSTEM=="usb", ATTR{idVendor}=="2080", MODE="0666", GROUP="plugdev" #Nook
SUBSYSTEM=="usb", ATTR{idVendor}=="0955", MODE="0666", GROUP="plugdev" #Nvidia
SUBSYSTEM=="usb", ATTR{idVendor}=="2257", MODE="0666", GROUP="plugdev" #OTGV
SUBSYSTEM=="usb", ATTR{idVendor}=="10a9", MODE="0666", GROUP="plugdev" #Pantech
SUBSYSTEM=="usb", ATTR{idVendor}=="1d4d", MODE="0666", GROUP="plugdev" #Pegatron
SUBSYSTEM=="usb", ATTR{idVendor}=="0471", MODE="0666", GROUP="plugdev" #Philips
SUBSYSTEM=="usb", ATTR{idVendor}=="04da", MODE="0666", GROUP="plugdev" #PMC-Sierra
SUBSYSTEM=="usb", ATTR{idVendor}=="05c6", MODE="0666", GROUP="plugdev" #Qualcomm
SUBSYSTEM=="usb", ATTR{idVendor}=="1f53", MODE="0666", GROUP="plugdev" #SK Telesys
SUBSYSTEM=="usb", ATTR{idVendor}=="04e8", MODE="0666", GROUP="plugdev" #Samsung
SUBSYSTEM=="usb", ATTR{idVendor}=="04dd", MODE="0666", GROUP="plugdev" #Sharp
SUBSYSTEM=="usb", ATTR{idVendor}=="054c", MODE="0666", GROUP="plugdev" #Sony
SUBSYSTEM=="usb", ATTR{idVendor}=="0fce", MODE="0666", GROUP="plugdev" #Sony Ericsson
SUBSYSTEM=="usb", ATTR{idVendor}=="2340", MODE="0666", GROUP="plugdev" #Teleepoch
SUBSYSTEM=="usb", ATTR{idVendor}=="0930", MODE="0666", GROUP="plugdev" #Toshiba
SUBSYSTEM=="usb", ATTR{idVendor}=="19d2", MODE="0666", GROUP="plugdev" #ZTE
SUBSYSTEM=="usb", ATTR{idVendor}=="0414", MODE="0666", GROUP="plugdev" #Gigabyte

#Ejecutar el comando:
sudo udevadm control --reload-rules
#Esto con el objetivo de no reiniciar tu PC
#Y refrescar los Udev en "caliente"


#Por ultimo simplemente volver a conectar nuestro device a la computadora y ejecutar
adb devices

List of devices attached
M4 SS1070       device



martes, 18 de julio de 2017

miércoles, 1 de marzo de 2017

Seguridad con SpringBoot y CSRF

La seguridad con con Springboot es realmente sencilla.
Para activar la Basic Html, simplemente creamos un conjunto de clases de esta forma:

@EnableWebSecurity
@Configuration
@EnableSpringHttpSession
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Value("${com.pmj.dyo.configuration.security.user}")
    private String user;

    @Value("${com.pmj.dyo.configuration.security.password}")
    private String password;
    
    @Value("${com.pmj.dyo.configuration.csrf.login}")
    private String loginPage;
    
    @Value("${com.pmj.dyo.configuration.csrf.allow}")
    private String[] patterns;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().antMatchers(patterns).permitAll().and().csrf().disable().httpBasic().and()
                .addFilterAfter(csrfFilter(patterns), FilterSecurityInterceptor.class)
                .addFilterAfter(new CsrfGrantingFilter(loginPage), CsrfFilter.class);
    }

    private Filter csrfFilter(String[] patterns) {
        CsrfFilter csrfFilter = new CsrfFilter(csrfTokenRepository());
        csrfFilter.setRequireCsrfProtectionMatcher(csrfProtectionMatcher(patterns));
        return csrfFilter;
    }

    private NoAntPathRequestMatcher csrfProtectionMatcher(String[] patterns) {
        return new NoAntPathRequestMatcher(patterns);
    }

    private CsrfTokenRepository csrfTokenRepository() {
        HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
        repository.setHeaderName(X_XSRF_TOKEN);
        return repository;
    }

    /**
     * bCryptPasswordEncoder
     * 
     * @return
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

    /**
     * configureGlobal
     * 
     * @param auth
     * @throws Exception
     */
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser(user).password(password).roles("USER");
    }

    /**
     * sessionRepository
     * 
     * @return
     */
    @Bean
    @SuppressWarnings("rawtypes")
    public SessionRepository sessionRepository() {
        return new MapSessionRepository();
    }

    /**
     * sessionStrategy
     * 
     * @return
     */
    @Bean
    public HeaderHttpSessionStrategy sessionStrategy() {
        return new HeaderHttpSessionStrategy();
    }

    /**
     * @return the user
     */
    public String getUser() {
        return user;
    }

    /**
     * @param user
     *            the user to set
     */
    public void setUser(String user) {
        this.user = user;
    }

    /**
     * @return the password
     */
    public String getPassword() {
        return password;
    }

    /**
     * @param password
     *            the password to set
     */
    public void setPassword(String password) {
        this.password = password;
    }
}

////////////////////////////////////////////////////////////////////////////////////////////


public class CsrfGrantingFilter implements Filter {

    public static final String X_XSRF_TOKEN = "X-XSRF-TOKEN";

    private String loginPage;

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    /**
     * Login Page injection
     * @param loginPage
     */
    public CsrfGrantingFilter(String loginPage) {
        this.loginPage = loginPage;
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {
        CsrfToken csrf = (CsrfToken) servletRequest.getAttribute(CsrfToken.class.getName());
        String token = csrf.getToken();
        if (token != null && isAuthenticating(servletRequest)) {
            servletRequest.setAttribute(X_XSRF_TOKEN, true);
        } else {
            servletRequest.setAttribute(X_XSRF_TOKEN, false);
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    private boolean isAuthenticating(ServletRequest servletRequest) {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        return request.getRequestURI().equals(loginPage);
    }

    @Override
    public void destroy() {
        LogUtil.info(log, this.toString());
    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        LogUtil.info(log, filterConfig.toString());
    }
}

///////////////////////////////////////////////////////////////////////////////

@RequestMapping(method = POST, path = "", produces = APPLICATION_JSON_VALUE)
    public Map login(@RequestBody UserEntry userEntry, ServletRequest servletRequest,
            ServletResponse servletResponse) {
        boolean xsrfAvailable = (boolean) servletRequest.getAttribute(X_XSRF_TOKEN);
        Authorization aut = client.login(userEntry);
        Map resolve = new HashMap(); 
        if (aut != null && aut.isAccepted() && xsrfAvailable) {
            CsrfToken csrf = (CsrfToken) servletRequest.getAttribute(CsrfToken.class.getName());
            String token = csrf.getToken();
            HttpServletResponse response = (HttpServletResponse) servletResponse;
            Cookie cookie = new Cookie(X_XSRF_TOKEN, token);
            cookie.setPath("/");
            cookie.setSecure(true);
            response.addCookie(cookie);
            resolve.put(STATUS, AUTHORIZED);
            resolve.put(USERNAME, username);
            resolve.put(PASSWORD, password);
            resolve.put(ROLE, aut.getRole());
            resolve.put(TOKEN, token);
        } else {
            resolve.put(STATUS, UNAUTHORIZED);
        }
        return resolve;
    }


Básicamente lo que sucede en este ejemplo es lo siguiente:
  1.  El punto de control que genera el Cross Site Request Forgery es /login
  2. Si el login no es efectivo el CSRF no aparece como set en el cookie
  3. Ahora bien el toque esta en que el body también presenta el basic autentification y el CSRF. De esta forma es mas sencillo que el Javascript almacene los datos.
  4. Cada nuevo request debe enviar los Basic Login y el CSRF.
Dentro de la aplicacion pasa esto:
  1.  La aplicacion fija el toking en el login. 
  2. Si cualquier otro request que no este en la lista de permitidos es invocada. Revisa el Basic Aut y el CSRF toking. La clase que genera los toking es CsrfGrantingFilter.

martes, 21 de febrero de 2017

Java Poi con Maven y Springboot Restful (Usando imagenes)

Este articulo no es un "tutorial". Es un conjunto de notas de mi experiencia.
Si vas a adentrarte en este articulo. Debes conocer como usar POI. Maven y Springboot Restfull.

 Lo primero que debemos hacer es configurar el POM del maven para usar  todas las características de excel. Claramente algunas no son necesarias. Pero es mejor tenerlas para usar TODO lo que Excel ofrece:


      dom4j
      dom4j
      1.6.1
  
  
   org.apache.poi
   poi
   3.9
  
  
   org.apache.poi
   poi-ooxml
   3.9
  
  
      org.apache.commons
      commons-collections4
      4.1
  
  
      org.apache.xmlbeans
      xmlbeans
      2.3.0
  

Ahora bien para generar reportes POI ofrece varias características principalmente varias vistas de distintos tipos. Para no complicarse vamos a usar lo que SpringBoot ofrece.


No es recomendable... generar los reportes como stream dentro de los HttpServletResponse . Porque se puede cortar el request y el reporte quedar corrupto. Usar siempre las vistas.

//Lo primero debemos escojer un view que se ajuste a las necesidades. Al final hablare de los distintos tipos
public class ExcelBuilder extends AbstractXssfStreamingView {

    @Override
    public void buildExcelDocument(Map model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
        //Aqui ya vienen inicializado el workbook.
        //La unica funcion es implementar. Seria; Crear el sheet, crear filas, celdas, poner estilos, etc
        //No debemos preocuparnos por escribir el workbook en el response. Solo dejemos que el metodo termine.
        //Y Spring sabe que debe tomar el workbook y generar un archivo.
    }

}

//Debemos configurar que la vista sea usada para los endpoint
//Sencillamente podemos usar esto:
@Configuration
public class ExcelBuilderConfig {
    
    @Bean
    public ExcelBuilder ExcelBuilder() {
        return new ExcelBuilder();
    }

}

//Ahora bien solo resta usarlo en algun endpoint
@Api(value = "contest", description = "the contest API")
public interface ContestApi {

    /**
     * contestApplicantExport
     *
     * @param contest
     * @param brandid
     * @return
     */
    @ApiOperation(value = "", notes = "Returns a excel file report according to the information provided (A5:ContestApplicantExport)")
    @ApiResponses(value = {@ApiResponse(code = 200, message = "gallery response"),
            @ApiResponse(code = 200, message = "unexpected error")})
    @RequestMapping(value = "/contest/{contest}/{brandid}", produces = {
            "application/ms-excel"}, method = RequestMethod.GET)
    @org.springframework.web.bind.annotation.GetMapping("/dyo-config")
    ModelAndView contestApplicantExport(
            @ApiParam(value = "Filter based on a specific contest", required = true) @PathVariable("contest") String contest,
            @ApiParam(value = "Filter based on a specific brand", required = true) @PathVariable("brandid") String brandid,
            @ApiParam(value = "HttpServletResponse to setup the excel ouput", required = true) HttpServletResponse response);
}



@Configuration
@RestController
public class ContestApiController implements ContestApi {


    @Override
    public ModelAndView contestApplicantExport(
            @ApiParam(value = "Filter based on a specific contest", required = true) @PathVariable("contest") String contest,
            @ApiParam(value = "Filter based on a specific brand", required = true) @PathVariable("brandid") String brandid,
            @ApiParam(value = "HttpServletResponse to setup the excel ouput", required = true) HttpServletResponse response) {

        Book book = /*Cualquier Objecto*/
        return new ModelAndView("ExcelBuilder", "book", book); //Note que "book" es el dato que se puede obtener de la vista
    }
}

Los diferentes tipos de vistas presentes generan diferentes tipos de workbook.
Cada una con características diferentes:
Podemos mencionar XSSFWorkbook and SXSSFWorkbook.

La clase AbstractXssfStreamingViewes funcional para archivos muy grandes. Sin embargo tiene la tendencia a no funcionar de buena manera con las imágenes. Puede que te tengas que enfrentar a Streaching o a resize ridículos. Después de muchos intentos y de canas verdes. Descubrí que si uno quiere insertar imágenes. La mejor forma es usando XSSFWorkbook.

Para eso escribí mi propia versión de un AbstractXlsxView.

//Simplemente hacemos esto:
public abstract class AbstractXssfStreamingView extends AbstractXlsxView {

    @Override
    protected XSSFWorkbook createWorkbook(Map model, HttpServletRequest request) {
        return new XSSFWorkbook();
    }

}

//Y lo utilizamos:
public class ExcelBuilder extends AbstractXssfStreamingView {

    @Override
    public void buildExcelDocument(Map model, Workbook workbook, HttpServletRequest request, HttpServletResponse response) throws Exception {
        Book book = (Book) model.get("book"); //Usar de referencia al ejemplo de arriba para obtener los datmos del model
        //Tu codigo aqui
    }

}

//En el codigo de ejemplo para agregar imagenes creo un pequeno factory.
//La implementacion es por un conjunto de intefacez de esta manera:

@FunctionalInterface
public interface CellProduceInterface {

    /**
     * update
     * 
     * @param excelCell
     * @param data
     * @param workbook
     * @param sheet
     * @param point
     */
    public void update(org.apache.poi.ss.usermodel.Cell excelCell, Cell data, Workbook workbook, Sheet sheet, Point point);

}

//Y su implementacion
//Notas:
//El excelCell es el cell de POI
//El data es el modelo de la informacion de la celda
//Woorkbook asociado con la vista 
//Sheet actual en que que excelCell esta presente
public class ImageCellProduce implements CellProduceInterface {

    private static final Logger log = LoggerFactory.getLogger(ImageCellProduce.class);

    @Override
    public void update(org.apache.poi.ss.usermodel.Cell excelCell, Cell data, Workbook workbook, Sheet sheet,
            Point point) {
        String path = (String) data.getValue();
        if (path != null) {
            byte[] bytes = ExcelUtil.convertImagePathToBytes(path);
            if (bytes.length > 0) {
                int pictureIdx = workbook.addPicture(bytes, Workbook.PICTURE_TYPE_PNG);
                CreationHelper helper = workbook.getCreationHelper();
                Drawing drawing = sheet.createDrawingPatriarch();
                ClientAnchor anchor = helper.createClientAnchor();
                //Col and Cell pos
                anchor.setCol1(point.y);
                anchor.setRow1(point.x);
                //Height is not possible without stretched the image
                Picture pict = drawing.createPicture(anchor, pictureIdx);
                if (data.getWidth() != -1) {
                    sheet.setColumnWidth(point.y, ExcelUtil.calculatePoiWidthSize(data.getWidth()));
                    data.setWidth(-1);//Asi no se vuelve a aplicar el estilo mas adelante
                }
                if (data.getHeight() != -1) {
                    excelCell.getRow().setHeight((short) ExcelUtil.calculatePoiWidthSize(data.getHeight()));
                    data.setHeight(-1); //Asi no se vuelve a aplicar el estilo mas adelante
                }
                data.setAutoSize(false);
                pict.resize(); //Como es XSSFWorkbook no deberia presentar problemas con el size y mantiene el original
            }
        } else {
            log.info("ImageCellProduce: Ignoring image on " + point);
        }
    }

}

miércoles, 6 de abril de 2016

Provar en local enviar correos con Postman

Creo que esto podría servir para cualquier tecnología. Pero me voy a enfocar en el plugin de Postman para wordpress en PHP.

Pasos:

1.) Debemos instalar Python con todos los utilitarios.

2.) Ejecutar el comando en una terminal
Nota: La terminal mostrara en consola todo los correos que se envíen a este servidor de pruebas.

sudo python -m smtpd -n -c DebuggingServer localhost:45

3.) Debemos ir a la configuración del postman del wordpress.
Luego en Configuración manual.



Dentro es simplemente de poner:

Outgoing mail server hostname:......127.0.0.1
Outgoing mail server port:................45
Security:..............................................None
Authentication:...................................None


4.) Enviamos un mail de pruebas.


5.) Este correo lo podremos ver en la terminal.



jueves, 17 de marzo de 2016

Kde Kate con React.js y Syntaxis Hightlight

Para los que me siguen en el blog, saben que mi entorno de escritorio favorita es KDE. Y para desarrollo web en especial para Javascript utilizo Kate.
Resulta que React.js esta muy de modo hoy en día, entonces me di a la tarea de investigar y aprender un poco.
Para mi sorpresa, React.js tiene una sintaxis algo "Jodida". Y no se puede interpretar como Javascript normal.
Entonces tome el Synstaxis Higtlight de Javascript que viene por defecto en Kate y lo edite para que funcione con React.js
(Por cosas como estas amo el software libre).

Simplemente tiene que colocar este archivo:





  
    
       break 
       case 
       catch 
       const 
       continue 
       debugger 
       default 
       delete 
       do 
       else 
       finally 
       for 
       function 
       if 
       in 
       instanceof 
       new 
       return 
       switch 
       this 
       throw 
       try 
       typeof 
       var 
       void 
       while 
       with 
    
    
       class 
       enum 
       export 
       extends 
       import 
       super 

      
       implements 
       interface 
       let 
       package 
       private 
       protected 
       public 
       static 
       yield 
    
    
       Infinity 
       NaN 
       false 
       null 
       true 
       undefined 
    
    

      
      
      
        
      

      
        
        
        

        
        
        
        
        

        
        
        

        
        
        
        
        
        
        

        
        

        
        
        

        
        

        
        

        

        
        

      

      
        
        
        
        
        
        
      

      
        
        
        
        
      

      
        
        
      

      
        
        
        
        
        
        
      

      
        
        
        
      
      
        
        
        
      

      
        
        
      
      
        
        
        
      

      
        
        
        
        
        
        
        
        
      
      
        
        
        
      
      
        
      
      
        
      

      
        
        
      

      
        
        
        
        
        
        
      
      
        
        
        
        
        
        
     
     
        
        
     


    
    
      
      
      
      
      
      

      
      
      
      
      
      

      
      
      
      
      
      
      

      
      

    
  
  
    
      
      
    
    
  


con el nombre. react.xml.

En el folder: ~/.kde/share/apps/katepart/syntax/

Nota: Esta es la primera versión del asunto.
Supongo que la tendré que ir madurando. Cualquier Feedback sera mas que bienvenido.

domingo, 4 de octubre de 2015

Instalar Nvidea Dirver/Steam en Debian 8


Pasos:

1. Agregar el el repositorio al administrador de paquetes
sudo nano /etc/apt/sources.list
#deb http://http.debian.net/debian/ jessie main contrib non-free
sudo apt-get update

 2. Activar multiarquitectura
sudo dpkg --add-architecture i386
sudo apt-get update

3. Instalar el paquete:
sudo apt-get install libgl1-nvidia-glx:i386
sudo apt-get install steam


4. Crear el archivo:

/etc/X11/xorg.conf.d/20-nvidia.conf

Con el contenido:

Section "Device"
        Identifier "My GPU"
        Driver "nvidia"
EndSection

5. Reiniciar

lunes, 31 de diciembre de 2012

Apache para drupal 7 en Linux (Problemas con Clean URL)

Hace algún tiempo me he empezado a interesar en Drupal 7. Honestamente me ha gustado mucho, la idea esta bien planteada. La documentación esta bien y el soporte de la comunidad. En futuras entradas hablare de los módulos. Por ahora quiero hablar un poco sobre los requisitos necesarios y sobre todo de Apache y su configuración.

Verán instalar Drupal 7 es un juego de ninos. Podrían buscar en Internet miles de entradas de como instalarlo. Por eso no me parece útil referirme al tema.

Una vez instalado ya tienen su sistema instalado en localhost. Y digamos que quieren ingresar a la pagina de autentificación de ususario.
Deberian acceder a la siguente pagina:

http://127.0.0.1/kcontrol/user

Pero sorpresa, SORPRESA!!!
La pagina no existe. Bienvenido al problema de los cleanURL.
Para poder acceder esta pagina deberian usar:

http://127.0.0.1/kcontrol/?q=/user

Porque?
El .htaccess de Apache es un archivo que te permite escribir reglas especializadas para que los clean url funcionen en Drupal 7. Por defecto no vienen configuradas en nuestro Apache de linux mediante de los repositorios (sudo apt-get install apache2)

Por eso vamos a hacer un par de ajustes para que sirvan:

1. Primer paso instalar apache y todas las dependencias:

#!/bin/bash
sudo apt-get install apache2 php5 libapache2-mod-php5 php5-gd php5-dom php5-pgsql


Note que yo uso Postgrest SQL. Por eso el paquete php5-pgsql pero para los mysql adictos debería ser php5-mysql

2. Modificar el archivo /etc/apache2/sites-available/default
Remplazar:
"AllowOverride none" por "AllowOverride All"


3. Habilitar el modulo de rewrite rules

#!/bin/bash
sudo a2enmod rewrite
sudo service apache2 restart

Listo!!!

miércoles, 30 de mayo de 2012

Convertir el color de una imagen a transparente con bash...

Hace tiempo atrás me había enfrentado a la tarea de quitar un color de una imagen en BMP y sustituirla por transparencia.

Nota: Por razones de derechos de autor no puedo poner las imágenes, pero puedo poner el link donde están:

http://www.reinerstilesets.de/

Para recrear lo que quiero hacer es algo como esto:
Cambiar el cafe y ponerlo trasparente
 

Esas imágenes son geniales para programar juegos con SDL. Ya que necesitamos un color key que podamos "sacrificar". Pero si lo queremos usar en algún lenguaje que soporte transparencia como Java.

R// Muy fácil dirán unos, abrís GIMP y seleccionas con Magic Choose el color deseado lo cortas y lo salvas.

Es verdad, pero hacerlo para 1000 imágenes...
VERDAD? que no es tan fácil.

La solución a nuestros problemas es simplemente un script en bash que hagarra todas las imágenes las convierta y borre las originales.

El comando que necesitamos es este:

convert -transparent 'RGB()' imagenOrigen.bmp imagenDestino.png

El script quedaria

#!/bin/bash
FILES=`find $1 | grep bmp`
for f in $FILES
do
    nf=`echo ${f//bmp/png}` #replace all
    echo $nf
    convert -transparent 'RGB(97,68,43)' $f $nf
    rm $f
done

Y para usarlo basta llamar el script y darle el folder con todas las imagenes

viernes, 20 de enero de 2012

El meollo de las librarias y el proceso de linkeo en C++

Uno de los compiladores más completos que cumple con todas las normas ISO de C++ Gcc sobre linux. Y quiero compartir lo que he aprendido en los últimos años de programación.
Lo primero que siempre me costo es el linkeo y que es este condenado proceso:
Bueno el linkeo es el paso de anexar bibliotecas a nuestro código objeto (Source code compilado) generando una imagen binaria.
Un ejemplo hiper sencillo. El clásico holamundo.cpp

//holamundo.cpp
#include <iostream>
using namespace std;
int main() {
    cout << "Hola Mundo" << endl;
    return 0;
}
./hola


El comando genera en silencio un binario con la salida de hola (Parametro -o) del sorce code (seguido de g++)
Para correrlo simplemente usamos

g++ holamundo.cpp -o hola

Este archivo utiliza una librería implícita que es la iostream. Por ende el linkeo se da correctamente.
Pero imagina que queremos hacer algo mas complejo. Algo que necesite de librerías adicionales para trabajar. Bueno que tal si creamos una librería súper sencilla para servir de ejemplo. Con esto se aclararan muchas dudas. Pero lo primero.
Nota: La librería que vamos a crear es conocida como librería estática. Esta es un poco mas pesada. que una dinámica. Y se encuentra en ubicaciones no estandar.( /usr/include y /usr/lib). La dificultad para crear una biblioteca dinámica es nula. Pero lo dejare para futuras entradas.

//koza.h
#ifndef MENSAJE_H
#define MENSAJE_H
int getMessage();
#endif
 
//koza.cpp
#include <iostream>
#include "koza.h"
int getMessage(){
    return 25;
}

Ahora si a crear nuestra biblioteca.

g++ -c koza.cpp -o libkoza.o
ar rcs libkoza.a libkoza.o

Ahora si. La hablada. El primer comando crea un archivo objeto de nuestro source sin linkear. (comando -c). La salida (comando -o) es libkoza.o. Esto es un estándar para bibliotecas. Siempre deben empezar con lib#Nombre#.a (En el caso de las librerías estáticas).
Ahora si tenemos nuestra libreria y nuestro archivo de inlcusion.
Simulemos un ambiente de mas o menos de esta forma.
Primero nuestro archivo de ejemplo para que utilice la biblioteca.

//mostrar.cpp
#include <iostream>
#include "koza.h" //Se incluye la cabecera de esta forma porque es bilioteca estatica (dinamica es con <>)
using namespace std;
int main(){
    cout << getMessage() << endl;
    return 0;
}

Simulemos la siguiente estructura de archivos.
/home/koza/ejemplo/mostrar.cpp
/home/koza/ejemplo/include/koza.h
/home/koza/ejemplo/lib/libkoza.a
ahora si a compilar

g++ /home/koza/ejemplo/mostrar.cpp -I/home/koza/ejemplo/include/ -L/home/koza/ejemplo/lib/ -lkoza

Ahora si que sucede.
El Parámetro -I le dice la ruta de los archivos de inlcusion.
El Parámetro .L le dice la ruta de los archivos de librerías
y el comando -lkoza -> La librería a incluir es libkoza.a PORQUE? Pues por el estándar. el busca el nombre de la librería después del -l#NAME según el nombre libkoza.a.
Ese fue un ejemplo muy troglodita.
Veamos algo mas útil.
Nota: Debemos tener instaladas las bibliotecas de QT4.
Vamos a compilar un ejemplo de holamundoqt.cpp

//holamundoqt.cpp
#include <qapplication>
#include <qpushbutton>

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);
    QPushButton hello("Hello world!");
    hello.resize(100, 30);
    hello.show();
    return app.exec();
}

Qt es una librería para hacer muchas cosas, entre ellas interfaces gráficas.
Bueno es hora de compilar el ejemplo de arriba. Como verán se ocupan un montón de librerías. Entonces a jugar.

g++ holamundoqt.cpp -o hola -I/usr/include/qt4 -I/usr/include/qt4/QtGui -L/usr/lib/qt4 -lQtCore -lQtGui

Hay una herramienta que nos ayuda mucho a la hora de realizar linkers de nuestros programas.
Es la poderosa pkg-config.
Simplemente es una herramienta que ayuda a la hora de completar los comandos de compilación. Generando los parámetros -I -L -l necesarios para compilar.
Para conocer los paquetes instalados usamos:

pkg-config --list-all

El nombre que se genera a la izquierda es el paquete que podemos usar.
En el ejemplo de qt de arriba el siguiente comando

pkg-config --cflags --libs QtGui

Muestra la siguiente salida.
-DQT_SHARED -I/usr/include/qt4 -I/usr/include/qt4/QtGui -I/usr/include/qt4/QtCore -lQtGui -lQtCore
Es precisamente todos los comandos que escribimos arriba. Haciendo uso de esta herramienta y de los pipes. El programa de holamundoqt lo podemos compilar tambien de esta forma:

g++ holamundoqt.cpp -o hola `pkg-config --cflags --libs QtGui`

martes, 18 de octubre de 2011

Algunos trucos con el httpd.conf y php.init

Php en su archivo de configuración tiene una serie de atributos interesantes. Muchos de los cuales en mi vida he visto y otros que no les presto mucha importancia. Curiosamente hace un par de semanas atrás, mi jefe directo me asigno una misión bastante peculiar. Tenia que hacer funcionar local un aplicación. No voy a rondar en detalles. Si los quieren leer pueden verlos aquí.

En mi búsqueda de hacer funcionar dicha aplicación me tope con algunas variables en los archivos de configuración en el php y en el apache que quiero compartir por aca:
 
Primer truco

Uno muy interesante es poder anular los warning en php.
Usando la variable siguente en el php.init:

error_reporting = E_ALL & ~E_NOTICE

Esto le dice al Php que muestre los errores, pero no los warning o Notice como se les conoce. Entonces imaginemos que en el php creamos un array o tratamos de acceder alguna variable global y después simplemente tratamos de acceder sus datos con un índice que no existe.

Ejemplo:

echo $_REQUEST["email"]; 

Si esta variable no se encuentra configurada en el php.init, el warning es mostrado.

Sin embargo puede presentar problemas intensos de hackeo. Yo no recomendara utilizarlos.

Segundo Truco

Otro truco que si me parece mas util de usar es el: auto_prepend_fileauto_append_file. Estos son archivos que se cargan al inicio de cualquier script y despues de cualquier otros script en su orden respectivamente.

Un ejemplo seria algo asi como:
auto_prepend_file = /home/sites/koza/phpdefines.php

Esta variable auto carga o auto ejecuta este script antes de cualquier ejecusion. Es equivalente a:

inlcude('/home/sites/koza/phpdefines.php');

En el incio de cualquier script.

Tercer Truco

Ejecutar los script en php en archivos con extensión html. Al inicio pensé que esto seria de lo mas trivial del mundo. Honestamente confieso que me tomo más tiempo del que pensé. Realmente es trivial, pero encontrar el lugar para poner la configuración fue lo que me tomo mucho tiempo. Nota: Se puede hacer esto un archivo .httpaccess. Sin embargo no logre hacerlo funcionar por eso prefiero dejarlo como un nota (De que en teoría es posible).


En el archivo de configuración de apache (httpd.conf)

Buscamos la línea:

AddType application/x-httpd-php

Y le agregamos al final .htm y .html

Quedando algo asi como:

AddType application/x-httpd-php .htm .html

Esto es muy útil por razones de seguridad. Escondiendo en que esta programado la aplicación porque en el browser se vera simplemente .html en los scripts que en realidad son php. Pienso que es una excelente practica de configuración del los servidores.

Cuarto Truco.

Los virtual host, las configuración https y el /etc/hosts. Estos chicos pueden hacer una verdadera epifanía si no se sabe configurar bien. Hagamos algo básico y general. Los archivos hosts son archivos especializados dentro de los sistemas operativos (/etc/hosts para linux, unix y derivados) -> notese el s al final. Este archivo "simula" la llamada de un dominio remplazando por un ip previamente configurado.

Ejemplo:
127.0.0.1 koza.com

Si en el browser abro la dirección www.koza.com en realidad el archivo hosts se encarga de cargar mi servidor local.

Quinto Truco.

Los virtual Host son una noble invención, junto con el archivo host pueden hacer grandes hazanas.
Daremos por un hecho que existe en el archivo host la configuración anteriormente dada.

Entonces podemos construir de koza.com un mundo de reglas virtuales de nuestro sitio como:


        ServerName cruiser.koza.com
        UseCanonicalName Off
        DocumentRoot /home/sites/koza/htdocs/

    SetEnv SITE_LINK_URL http://www.google.com


En la configuracón arriba establecida le estamos diciendo al apache (Con ayuda del host file) que la proxima vez que alguien acceda a cruiser.koza.com su configuración personalizada va a usar Document Root en la carpeta /home/sites/koza/htdocs y que va a tener una variable de entorno personalizada llamada SITE_LINK_URL. Podemos hacer uso de esta en Php asi:

define("SITE_LINK_URL", $_SERVER["SITE_LINK_URL"]);

AEM hablemos del arquetipo 11

Cuando creamos un proyecto con AEM. Siempre es importante saber que arquetipo estamos usando. Pues esto me determinara que source, herramien...