18 dic 2009

Browser size de Google ¿una herramienta inutil?

Me podría llamar un seguidor de Google, ya que creo que es una compañia que generalmente desarrolla muy buenos productos. Como siempre se dice, nadie es perfecto, y creo que Google lo demostro con esta nueva herramienta Browser Size.

Debo ser sincero y decir de antemano que no la he probado demasiado, solo he realizado pruebas sobre algunos sitios, principalmente para ver en donde estaba la utilidad. Hasta ahora, he encontrado muy poco...

Me dí cuenta que la posible utilidad que tiene esta herramienta es... ayudar a la persona que recién se esta iniciando en la web, y esta lanzando su primer sitio.

Para aquellos que van a utilizar esta herramienta les aconsejo tener en cuenta lo siguientes puntos:

  • Hoy en día los sitios que son maquetados con css, y hasta con tablas, pueden definir un ancho variable dependiendo del tamaño de la pantalla del navegador. Por lo tanto, si vemos una página en Browser Size, en un monitor de 1680x1050, con el navegador maximizado, puede no ser la misma página que verá una persona en un monitor de 1024x768 (si la página es de ancho variable).
  • El informe de la cantidad de personas con diferentes resoluciones de monitor, también la tenemos disponibles en nuestro sitio web, en caso que utilicemos Google Analytics. Yo prefiero esta alternativa, para los sitios que ya están en funcionamiento, porque nos permite verificar la información con nuestros visitantes reales. Por ejemplo, si realizamos un sitio web para diseñadores, es muy probable que sus pantallas sean más amplias que la media, mientras que si es para personas mayores, es probable que la resolución sea mucho menor que la media. Obviamente, todo esto debe ser verificado contra nuestras estadísticas.
  • Existen herramientas, por ejemplo para Firefox, disponemos de una extensión llamada Window Resizer (https://addons.mozilla.org/en-US/firefox/addon/1985) que nos permite cambiar el tamaño de la ventana del navegador, para emular lo que es una resolución diferente a la que utilizamos normalmente.

Prefiero utilizar las herramientas alternativas para poder conocer que es visualizado por la mayoría de mis visitantes, y que queda fuera. Espero que Browser Size, tenga alguna funcionalidad extra que me estoy perdiendo.

Cerrando el post

Solo espero que Google comience a modificar un poco el rumbo de sus nuevos productos, si bien son innovadores (algunos de ellos), cada día me doy cuenta que se estan pareciendo más a lo que tantas veces se critico de Microsoft: productos de baja calidad. Si soy conciente que en los últimos tiempos Google ya dejo de ser esa empresa más inocente para los usuarios, a pasar a ser una empresa que esta intentando incrementar sus ingresos. Esto es perfecto, y como toda empresa debe seguir ese fin, pero lo que NO me gusta, es que siento que están cambiando su escencia por este fin (Uno puede cambiar la visión, o el objetivo, pero nunca la misión, sino es otra empresa). ¿El futuro me dará la razón, o sere esclavo de mis palabras?

10 dic 2009

¿Google Wave puede desplazar a Evernote?

Hoy, como todos los días, abrí EVERNOTE para guardar algunas notas y poder mantenerlas en un lugar independiente de la computadora que utilice, y en ese momento pense... ¿por que no uso Google Wave para esto? la respuesta es sencilla, aún no hay una interfaz de escritorio que me permita administrar la información como EVERNOTE.
Sería una muy buena alternativa el poder hacer una interfaz web que sea multiplataforma, al estilo EVERNOTE, pero utilizando Google Wave como backend. Aún no he investigado el protocolo de Wave, se que se puede hacer sin mayores complicaciones, pero por el momento no dispongo del tiempo para hacerlo.
Desde mi punto de vista, los beneficios que se podrían lograr utilizando Google Wave al estilo EVERNOTE, son lo siguientes:
  • Posibilidad de incluír extensiones a la información subida.
  • Posibilidad de compartir la información con otras personas dentro de Wave (incluír en el Wave a otros usuarios).
  • Google Wave tendrá mucha más integración con otras aplicaciones, que EVERNOTE.
  • Google Wave es totalmente gratuito, independientemente de la cantidad de información subida/descargada.
  • La búsqueda se hace con Google.
Como no todo es maravilloso en la vida, aún faltan mejorar los siguientes puntos:
  • Posibilidad de compartir un Wave publicamente.
  • Que Google Wave sea un poco más estable (he tenido problemas con Waves largos).
  • Que se pueda desarrollar una aplicación multiplataforma para la administración de Waves.
  • Que se pueda hacer más amigable la interfaz de Wave para este tipo de información.
Por el momento, deberemos seguir esperando a ver como se van desarrollando los hechos con Google Wave. Como sabemos Google Wave esta en beta aún, y tiene varias cosas por mejorar, pero estoy convencido que en el futuro tiene muchas posibilidades de ofrecer beneficios realmente interesantes... esto que planteo, será uno de ellos? paciencia.

3 dic 2009

YouTube para todos con YouTube Feather


El 18 de Noviembre asistí a una charla de YouTube organizada en CAME (Camara Argentina de la Mediana Empresa), y lo expuesto por Ricardo Blanco se cumplió, YouTube esta apostando a que todas las personas puedan acceder al servicio, mejorando la calidad y la velocidad del mismo.

La exposición de Ricardo fue muy buena, selecciono muy buenos ejemplos para que todos los asistentes podamos ver el poder que esta teniendo YouTube, y las herramientas que esta ofreciendo.

Poco tiempo atrás YouTube incorporaba la posibilidad de subir, y ver, videos en alta definición (1080p), hoy recibí a través de @YouTubeES una muy buena noticia, que YouTube esta lanzando YouTube Feather. YouTube Feather es lo que se va a venir en YouTube, por el momento esta en estado beta, nos permitirá tener una excelente calidad de video, necesitando un ancho de banda menor y menor poder de procesamiento (Parece especialmente desarrollado para America Latina).

Aún no he podido probar como funciona el nuevo YouTube Feather, solo he visto un video, por lo cual no puedo aún dar un veredicto. Al igual que Google, YouTube (ya una empresa de Google) esta minimizando sus interfaces, para poder mejorar la experiencia del usuario (estamos volviendo a las raíces?)

Para ver algo más de YouTube Feather, que mejor que la página del producto http://www.youtube.com/feather_beta

1 dic 2009

Como transferir archivos con NuSOAP

Gracias al comentario de un visitante a mi blog, me dí cuenta que no había incluído ejemplos de como transferir archivos mediante un servicio web, más precisamente utilizando NuSOAP.
Por lo tanto hoy realice un ejemplo muy sencillo que nos permite hacer precisamente eso, tener un servidor corriendo NuSOAP, y que un cliente realice una petición y el servidor retorne el archivo solicitado por el cliente.

Servidor para transferir archivos

El servidor es muy similar al ejemplo que utilice en el primer post que realice en mi blog sobre este tema (http://www.orlandobrea.com.ar/2009/09/webservices-con-nusoap-en-php-ejemplo-1.html). Voy a ir directamente al ejemplo, ya que todo lo necesario para entender el mismo ya lo he explicado en los posts anteriores.
// Archivo nusoap_server_ejFile.php
<?php
require_once('nusoap/lib/nusoap.php');
$miURL = 'http://pruebas.orlandobrea.com.ar/nusoap_ej1';
$server = new soap_server();
$server->configureWSDL('ws_orlando', $miURL);
$server->wsdl->schemaTargetNamespace=$miURL;




$server->register('getArchivo', // Nombre de la funcion
 array('nombre' => 'xsd:string'), // Parametros de entrada
 array('return' => 'xsd:string'), // Parametros de salida
 $miURL);
// Función que recibe el nombre del archivo que debe retornar.
// Lee el contenido del archivo cuyo nombre corresponde con el pasado
// como parámetro a la función, le aplica Base64 para codificar su
// contenido, y luego lo retorna como un string
function getArchivo($nombre){
 $archivo = file_get_contents($nombre);
 $archivo = base64_encode($archivo);
 return new soapval('return', 'xsd:string', $archivo);
}

$server->service($HTTP_RAW_POST_DATA);
?>

El cliente que recibe los archivos

El cliente también es muy similar al del primer ejemplo, por lo tanto ya vamos a lo importante, el código.
// Archivo nusoap_client_ejFile.php
<?php
require_once('nusoap/lib/nusoap.php');
// Crear un cliente apuntando al script del servidor (Creado con WSDL)
$serverURL = 'http://pruebas.orlandobrea.com.ar';
$serverScript = 'nusoap_server_ejFile.php';
$metodoALlamar = 'getArchivo';

$cliente = new nusoap_client("$serverURL/$serverScript?wsdl", 'wsdl');
// Se pudo conectar?
$error = $cliente->getError();
if ($error) {
 echo '<pre style="color: red">' . $error . '</pre>';
 echo '<p style="color:red;'>htmlspecialchars($cliente->getDebug(), ENT_QUOTES).'</p>';
 die();
}

// 1. Llamar a la funcion getArchivo del servidor, pasando como parámetro 'wallpaper_mac.png'
$result = $cliente->call(
    "$metodoALlamar",                     // Funcion a llamar
    array('wallpaper_mac.png'),    // Parametros pasados a la funcion
    "uri:$serverURL/$serverScript",                   // namespace
    "uri:$serverURL/$serverScript/$metodoALlamar"       // SOAPAction
);
// Verificacion que los parametros estan ok, y si lo estan. mostrar rta.
if ($cliente->fault) {
    echo '<b>Error: ';
    print_r($result);
    echo '</b>';
} else {
    $error = $cliente->getError();
    if ($error) {
        echo '<b style="color: red">Error: ' . $error . '</b>';
    } else {
 // Decodificación de la respuesta del servidor
 $contenido = base64_decode($result);
 // Guardar la respuesta del servidor, decodificada, en el archivo tmp.png
 file_put_contents("tmp.png", $contenido);
    }
}

?>
El código es bastante sencillo de enteder, simplemente se llama a getArchivo en el webservice del servidor, y se le pasa como parámetro el archivo que deseamos descargar (en este caso wallpaper_mac.png). El servidor retorna el archivo al cliente (codificado con base64). El cliente recibe el archivo y lo decodifica, luego lo guarda en un archivo "tmp.png".
El ejemplo es muy sencillo, y no es apto para un ambiente productivo. Para poder usar este ejemplo en un servidor productivo, deberíamos:
  • Agregar verificación de errores (Por ejemplo, que el archivo exista).
  • El servidor debe establecer ciertas reglas de seguridad (Por ejemplo que solo se pueda acceder a ciertos archivos)
  • Que el cliente pueda solicitar diferentes tipos de archivos (que el archivo a solicitar no este fijo como en el ejemplo, wallpaper_mac.png).
  • Que el archivo en el cual se guarda el archivo recibido, sea modificable.
Estos son solo algunas correcciones que deberíamos hacer para mejorar el código y que sea más seguro. Para los fines del ejemplo, preferí mantener el mismo lo más sencillo posible, para enfocarnos en lo importante en este caso.
Este ejemplo también esta disponible para su descarga.

25 nov 2009

Querés saber como podes utilizar Google Wave


(Inspirado en textos de Google Wave)

Hoy luego de seguir usando Google Wave, y estar muy contento con las funcionalidades que trae, decidí leer un poco de la documentación del mismo, que esta en Waves.




Empecemos por como funciona Google Wave

Antes de empezar con las ideas de uso de Google Wave, quiero dar una pequeña explicación de como funciona Google Wave, para aquellos que aún no lo probaron.
Google Wave maneja todo por Waves, que son algo así como un lugar donde ingresar y compartir información. Imaginemos un Wave como una hoja en blanco, que podemos crear, editar, borrar, archivar, y por sobre todas las cosas, compartir con otras personas. A diferencia de una hoja en blanco, que solo una persona puede estar asándola a la vez, es que en Google Wave, todos los que elegimos que puedan participar de dicha Wave, pueden editarla a la vez (o en tiempos diferentes).
Bueno, luego de haber hecho una muy breve introducción a que es Google Wave, comenzaré a desarrollar algunas de las ideas de uso de Google Wave (debo aclarar que me estoy inspirando en un texto de Google, no es una autoría mía, ni tampoco es una traducción literal del contenido; más bien es una inspiración para poder desarrollar sobre ella). Bueno, ahora si veamos como podemos usar esa hoja en blanco que nos ofrece Google Wave de forma más productiva que solo mirarla.


Como podés usar Google Wave


Organizar eventos

Mantener las ideas organizadas en un único lugar, como puede ser, el itinerario sugerido, el menú, la administración de los recursos, etc. Además se pueden incorporar el estado del clima, y mapas. Veamos, entonces podríamos organizar un evento, en el cual podríamos hacer el itinerario, si se realiza en diferentes lugares, con solo utilizar Google Maps e incorporarlo a nuestro Wave.


Notas de reuniones

Se puede preparar la agenda de una reunión entre varias personas, cada uno realizando notas, incorporando información, enlazando a documentos anexos (por ejemplo presentaciones PowerPoint), incorporando enlaces a sitios en los cuales podemos recopilar mayor información, etc. Todo esto en tiempo real, cada persona que participa del Wave puede ver los cambios al instante, y también realizar cambios en el momento que lo desee.
Una función muy útil de Google Wave es la llamada "Playback" que nos permite ver como se fue comportando el Wave, quién abrió el wave, que cambios se fueron realizando por cada persona. Es decir tenemos todo el historial, o sea que si por error perdimos información, no debemos preocuparnos porque sigue estando allí para recuperar.
Una vez finalizad la reunión se pueden realizar las notas finales en el mismo Wave o en uno nuevo. Podríamos invitar a todas las personas que participaron en un nuevo Wave, para que nos comenten su experiencia, y podemos incorporar una votación para que puedan calificar a la reunión.


Reportes de grupo y desarrollo de proyectos

Trabajar de manera colaborativa en tiempo real, realizando nuestros primeros bosquejos, discutir y solicitar feedback, todo en el mismo Wave. Nos ahorramos de enviar muchos e-mails con copias a diferentes personas, y luego ya no saber si a todos le enviamos la información que debíamos. A medida que los bosquejos van tomando más forma, se irán convirtiendo en proyectos, que pueden seguir desarrollandose en Wave.
Esta quizás es una de las funciones que yo más utilizo, desarrollo de proyectos, la cual utilizó para ir plasmando los nuevas ideas, y compartirlas con las personas que formarán parte de ella (y viceversa, que personas que tienen ideas, me incorporen a mi para formar parte del desarrollo del proyecto).


Brainstorming / Lluvia de ideas

Es una función que Google Wave permite realizar muy bien , principalmente cuando tenemos un grupo distribuido. Todas las personas pueden participar de un Wave escribiendo todas las ideas que le vienen a la cabeza, y todas en simultáneo.
También podemos ir incorporando imágenes, videos, enlaces externos, y hasta enlazarlos con otras Waves.
Luego ya tenemos toda la información, y solo nos resta comenzar a filtrar las ideas.


Compartir fotos

Se puede arrastrar y pegar (drag & drop) fotos desde el escritorio al Wave. Luego esas fotos se pueden compartir con otras personas. Existe un visor de fotos (slideshow) que nos permite ver todas las fotos de manera mucho más sencilla (es solo sentarnos y apreciarlas). Las demás personas que participan de la Wave también pueden subir sus fotos para que sean visibles por todos los integrantes de la Wave. Es muy sencillo poder hacer un álbum de fotos de un grupo con Google Wave.


Como uso yo Google Wave

Bueno, ya lo comente un poquito en este post, y en posts anteriores. Principalmente lo uso para abrir un Wave por idea, y compartirlo con diferentes personas que van agregando valor a la idea. Por ejemplo si se me ocurre que la venta de peces luminosos (idea extraída de The Big Bang Theory) puede ser buena, abro un Wave sobre este tema e invito a diferentes personas a que opinen sobre ella, y vayan aportando valor, hasta llegar a una idea potable, o descartarla por el momento.


Y ya cerrando este post

Ahora estoy intentando buscar nuevos usos a Google Wave, lo cual lo estoy intentando alcanzar por medio de otras personas que estoy sumando a mis contactos. Entre mis contactos tengo a personas de Marketing, y personas mucho más Técnicas (principalmente sistemas), es muy interesante ver los beneficios que puede traer a los diferentes tipos de personas. Sigamos descubriendo, esa es la única forma de crecer.

23 nov 2009

Google AdWords para sitios específicos


Como hace unos días recibí crédito de Google para abrir mi cuenta de AdWords, decidí comenzar a probar el servicio. Comento un poco mi experiencia anterior y el porque no probé anteriormente el servicio.

El sitio del cual ya hace un tiempo me encargo en administrar y posicionar, es un sitio para un sector especifico, y he logrado una muy buena posición en Google por las palabras claves detectadas. Como de esta forma, me resultaba conveniente y exitoso el posicionamiento del sitio web, me parecía que invertir en AdWords podría ser una perdida de tiempo y dinero. Dado que Google me dio crédito para AdWords, ya tenía 50% de mis excusas resueltas, solo me faltaba tiempo (pero decidí hacermelo para probar el servicio).

De esta forma comence a probar el servicio de AdWords de Google, luego de leer un poco y generar mis primeros avisos me dí cuenta que existian muchas variables en juego al crear una campaña y avisos en AdWords. Voy a comenzar definiendo algunos términos de AdWords para todos aquellos que aún no lo han probado:

Campaña: es un presupuesto asignado a una determinada forma de publicación y anuncios que deseamos publicar. Varios anuncios pueden pertenecer a una misma campaña. En la campaña definimos el costo diario que deseamos utilizar, las regiones en la cuales deseamos que aparezca nuestro aviso (si es solo para un país determinado, grupo de paises, etc.), los dispositivos en los cuales deseamos que sean visualizados nuestros anuncios (laptops, teléfonos, etc), y rango de fechas en las cuales la campaña estará activa.


Anuncio: es un aviso en el cual indicamos el texto/gráfico que deseamos que aparezca en la pantalla de nuestros potenciales. Cada anuncio pertenece a una campaña. Google recomienda que incorporemos más de un anuncio a la campaña para poder medir la efectividad de cada uno de ellos. Todos los anuncios utilizan el mismo presupuesto que la campaña, es decir, si asignamos $10 por día a una campaña, todos los anuncios que pertenecen a la campaña compartirán dicho presupuesto.


¿Cual fué mi experiencia?
Si bien no he realizado una investigación profunda de AdWords, he recopilado cierta información y experiencia con los anuncios que he publicado, la cual voy a detallar en los siguientes puntos:
  • Se debe realizar una elección adecuada del presupuesto a asignar a cada campaña, se debe tener en cuenta que el monto que uno indica que desea utilizar por día, no necesariamente es el que Google AdWords utilizará (hasta el momento AdWords siempre ha destinado mayor presupuesto por día del que le he asignado).
  • Se deben ingresar varios anuncios por cada campaña, intentando orientar cada uno a diferentes beneficios del producto/servicio que estamos intentando promocionar. Esto es útil para poder verificar la efectividad de los diferentes tipos de anuncios.
  • Se debe tener especial cuidado en las redes que incorporamos nuestros anuncios, una mala elección de las redes provocará una alta cantidad de clicks entrantes a nuestro sitio web, pero también una alta tasa de rebote. En un principio deje que Google gestionara las redes en las cuales promocionaba los anuncios, pero esto solo logro tener una muy alta cantidad de clicks (incrementando costos), pero una aún más alta tasa de rebote. O sea que el tráfico generado no pertenecia al público objetivo del anuncio.
  • Utilizar las herramientas de sugerencias de palabras claves, y de búsqueda de redes en las cuales incorporar los anuncios. Ambas herramientas son muy útiles para poder mejorar las visitas a nuestro sitio web.
  • Si tus productos son demasiados espécificos, la campaña debe ser de mayor duración y debe ser promocionada en sitios web que sean relevantes para tus productos/servicios. Mi experiencia indica que AdWords es mucho más útil cuando comercializamos productos o servicios que son masivos y principalmente para usuarios finales, pero cuando ofrecemos productos o servicios mucho más específicos debemos ser mucho más pacientes, y principalmente selectivos en la selección de los parámetros. Por ejemplo, si queremos promocionar una red social, sabemos que nuestro público objetivo es un rango bastante amplio de personas y el objetivo es estar en la mayor cantidad de sitios web posibles. En cambio, cuando hablamos de productos específicos, deseamos estar en sitios más selectivos, y ser más pacientes.
Hasta el momento he encontrado estos puntos como importantes para iniciar nuestras campañas en AdWords. Hasta el momento estoy convencido que es una muy buena herramienta para generar tráfico para sitios que ofrecen productos o servicios bastante masivos, pero no tan convenientes (a menos que modifiquemos bastante las opciones) para sitios mucho más específicos.
Antes de utilizar Google AdWords la tasa de rebote del sitio web que estoy administrando era de apróximadamente el 50%, cuando comencé a utilizar AdWords, la tasa subió a casí el 80%, he tenido que realizar muchas modificaciones a las campañas para intentar lograr que el porcentaje de rebote llegue, nuevamente, a valores de apróximadamente el 50%.
Con el tiempo, ire conociendo mucho más de la herramienta. Pero por ahora, sigo prefiriendo una buena posición en los buscadores (no en enlaces patrocinados / AdWords) y mejorar el posicionamiento por medio de técnicas de SEO tradicionales. Obviamente, las visitas es solo el comienzo del éxito de nuestro sitio web, luego debemos lograr que el visitante tenga una buena experiencia y se interese por lo que tenemos para ofrecerle.

17 nov 2009

Invitaciones gratuitas para Google Wave

Si sos usuario de Twitter, tenés que aprovechar la oportunidad que esta ofreciendo @ComunidadMktng para ganarte invitaciones para Google Wave.

Solo tenés que seguir los siguientes pasos:
- Iniciar tu sesión en Twitter
- Ir a @ComunidadMktng presionar sobre "Follow" o "Seguir"
- Visita el sitio de Comunidad Marketing y presiona sobre el botón verde en la parte superior derecha del artículo (para hacer RT / ReWeet de la noticia)

Con esos simples pasos ya estas participando por las 3 entradas de Google Wave. Apurate que el concurso es solo hasta el próximo lunes 23.


13 nov 2009

Prueba de AdWords productos específicos vs masivos

Hoy comence a realizar una prueba en AdWords diferente, un producto de venta masiva vs un producto para un sector muy especifico. Las diferencias son muy grandes, las posibilidades, las redes, y la información que se puede encontrar sobre los productos de venta masiva es muy buena, y útil. Para los productos muy específicos, no existen demasiados análisis, las redes son mucho más escasas, y hay que tener mucho cuidado con las redes seleccionadas.

Sigo pensando que Google AdWords es una herramienta genial para todas aquellas personas que desean llegar a un público muy amplio, y masivo. Es como un supermercado, en el mismo vamos a buscar productos que sirven para muchos tipos de personas, pero se nos hace muy difícil encontrar un producto muy específico en un supermercado (aunque hoy en día, ya no me sorprende lo que puede haber dentro de un supermercado).

El ejemplo de producto de venta masiva, lo realice sobre una empresa que basa sus productos en el cuidado de la piel (más precisamente sobre productos del cuidado de la piel MaryKay), y me resulto mucho más fácil encontrar redes en las cuales publicitar los anuncios, y también la información que me entregaba Google era mucho más útil. Si bien los resultados los iré viendo con el tiempo, si puedo decir que la cantidad de publico al cual podemos llegar es más que interesante. Luego depende de nosotros el hacer una buena campaña, y transformar los clicks en oportunidades/dinero o lo que deseamos obtener.

En cambio el producto específico, del cual no puedo dar demasiada información, es un producto de software específico para una industria en particular. Las redes disponibles son muy pocas, la información que entrega AdWords no es demasiada, y principalmente tuve que tener mucho cuidado, ya que en un principio había seleccionado que Google AdWords me gestionara las redes en las cuales publicar (gran error mío). Cuando seleccione que Google AdWords me gestionara las redes, Google agrego mis anuncios en sitios de programas gratis con una gran cantidad de visitas. Recibimos una gran cantidad de visitas en el sitio web, pero también una gran cantidad de rebotes.

¿Cual fue el problema? sencillo, que el público que visito el sitio web, no eran potenciales clientes del producto, sino personas que estaban buscando otro tipo de producto o programas gratis. Por eso debemos tener especial atención en la cantidad de clicks, es decir, tener clicks es muy bueno, siempre y cuando ellos vengan de potenciales clientes. Para entender esto voy a intentar hacer una analogía con el mundo físico. Si entregamos folletos de una carnicería en una zona en la cual todas las personas son vegetarianas, no estamos haciendo un muy buen trabajo. Es decir, podemos decir que entregamos muchísimos folletos y eso sería muy bueno. Pero si luego vemos que ninguna de esas personas eran potenciales, y por lo tanto no nos compraron carne, nos terminamos dando cuenta que hemos desperdiciado nuestro dinero.

Por eso debemos ser cuidadosos cuando elegimos nuestras campañas, y principalmente en las redes en las cuales se publican nuestros anuncios. Si trabajas con productos/servicios masivos, tu trabajo será mucho más fácil, en cambio si trabajas con productos/servicios mucho más específicos, vas a tener que trabajar un poco más (y principalmente va a ser mucho más difícil poder realizar una planificación).


12 nov 2009

Experiencia con el trackman marble de Logitech

Ya hace más de 2 meses que estoy utilizando el trackball de Logitech, más precisamente el Trackman Marble y estoy muy impresionado con lo adictivo que termino siendo el uso del mismo. Como comente en mi post anterior hacia mucho tiempo que no utilizaba un trackball, y los que había utilizado anteriormente eran operados con el dedo pulgar, este nuevo trackball que adquirí se opera con el dedo índice/mayor.

La experiencia fue y es excelente, no voy a realizar una comparativa con respecto a un mouse tradicional, ya que algo de ello ya lo he comentado en mi post anterior. En esta ocasión me voy a enfocar a comentar mi experiencia, y las diferencias con el trackball operado con el dedo pulgar.

Debe confesar que al principio me costo un poco adaptarme nuevamente al uso del trackball, pero luego de uno o dos días, ya me sentía mucho más comodo, y a la semana, ya lo sentía parte de mí. La adaptación consiste en dos partes, primero que debemos operar el mouse con nuestros dedos índice/mayor sin mover demasiado la mano, y la segunda es que debemos acostumbrarnos a presionar el botón derecho del mouse con el dedo pulgar, y el botón izquierdo con el dedo meñique (o el que nos quede más comodo).

Ventajas del trackball operado con el dedo índice/mayor

  • Tenemos mayor fuerza en nuestros dedos medios, y precisión, por lo tanto es mucho más sencillo mover la "bola" del mouse, y lograr una muy buena precisión.
  • Es muy fácil mover el cursor de una esquina de la pantalla a otra, ya que con un impulso importante con los dedos que operamos el mouse, el mismo logra una inercia y "mágicamente" el cursor continúa su desplazamiento.
  • La precisión lograda es mucho mayor que la que recuerdo haber logrado con un trackball operado con el dedo pulgar (quizás sea solo yo, pero no tengo tan buen control de mi dedos pulgares, como de mis dedos centrales).

Y ya cerrando el post...

Mi experiencia con los trackballs es que una vez que comenzas a utilizar uno de ellos, luego es muy difícil poder volver a un mouse tradicional. Como desventaja con respecto a los mouse tradicionales es el espacio que ocupa, es mayor, y por lo tanto es más difícil transportarlo en el, por ejemplo, bolso de la notebook.

Invito a todas las personas que tengan la posibilidad de probar un trackball, estoy seguro que les será de mucha utilidad. La regla, que he comprobado, es que si deseas utilizar el trackball principalmente para jugar, es más conveniente uno operado con el dedo pulgar, en cambio para diseño u operaciones con mayor precisión o uso normal, es más cómodo el trackball operado con el dedo índice/pulgar.

Yo te puedo ofrecer solo mi experiencia, pero al final, vos tenés la última palabra, y el poder de decisión es tuyo, solo debes ser objetivo con lo que lees, y analizar el uso que le deseas dar. Pero ante todo lo importante es "actuar".


11 nov 2009

Google Wave

Luego de esperar un tiempo que me llegue la invitación para probar Google Wave (http://wave.google.com) hoy me llegó la invitación. Aún no he podido realizar demasiadas pruebas, simplemente recorrí un poco la interfaz, con el tiempo ire posteando los avances que voy haciendo sobre las pruebas de este "nuevo" sistema de comunicación.

Creo que puede ser una muy buena alternativa para la realización de proyectos, por ejemplo para administrar contenido que estamos desarrollando. Podemos lanzar una idea o bosquejo al grupo de personas que deben participar, y luego cada uno va realizando sus aportes en el documento. Una vez generado, podemos pasar el contenido a otro sistema, por ejemplo wiki, sitio, o cualquier otra alternativa, o podemos dejarlo en Google Wave.

Siempre es interesante probar las nuevas tecnologías que van apareciendo, para saber si nos es útil para mejorar nuestra forma de trabajo, y/o tenerla en cuenta en el futuro. Cuando uno se acostumbra a las herramientas de colaboración, debo reconocer, que es muy difícil volver.

En el futuro seguire posteando sobre las pruebas y experiencias que vaya teniendo con Google Wave.


WebServices con NuSOAP en PHP - Ejemplo 3

Este el tercer ejemplo que voy a publicar de la comunicación entre el cliente y servidor de WebServices utilizando NuSOAP con un servidor PHP. Para aquellos que llegarón directamente a esta página, les recomiendo que primero lean el primer ejemplo de NuSOAP con PHP, y luego el segundo ejemplo de NuSOAP con PHP, antes de continuar con este. En este ejemplo en particular voy a modificar el ejemplo 2, para en vez de retornar un objeto, retornar una lista de objetos. En el ejemplo anterior, trate un caso muy particular, que es cuando necesitamos obtener un objeto desde el servidor, en este nuevo ejemplo, voy a obtener un listado de objetos. Muchas veces necesitamos un listado de algún tipo de objeto, por ejemplo, un listado de clientes, con este nuevo Servicio Web planteo este caso, en el cual el servidor nos devuelve un listado con todos los clientes que existen en el sistema.
Como veremos existen algunas modificaciones extras que debemos realizar para retornar un listado con los clientes. Primero debemos definir una estructura que contenga a la definición planteada en el ejemplo anterior, y luego realizar una conversión un poco más compleja (de un vector de objetos, a un vector de vector). También voy a incluír una clase de soporte, que nos ayudará a realizar las conversiones.

Módulo Servidor

Para simplificar la estructura del servidor, intente extraer toda la lógica de conversión en una clase extra (smart_soporte.php), así la lectura del código del servidor se mantiene lo suficientemente limpia como para que sea más fácil su entendimiento. En el ejemplo anterior el servicio web retornaba un cliente al consumidor/cliente de dicho servicio web, en este caso, retornaremos un listado de clientes. Debemos tener en cuenta que las respuestas deben ser convertidas a los tipos de datos básicos, por lo tanto para devolver una lista de clientes, debemos convertir dicha lista en un lista de listas que contengan como indices/keys/claves los atributos de la clase Cliente.
A continuación expongo el código del servidor:
<?php
// Pull in the NuSOAP code
require_once('nusoap/lib/nusoap.php');
require_once('soporte_obrea.php'); // Incluyo este archivo que tiene archivos para soporte de WS

$miURL = 'http://pruebas.orlandobrea.com.ar/nusoap';
$server = new soap_server();
$server->configureWSDL('ws_orlando', $miURL);
$server->wsdl->schemaTargetNamespace=$miURL;



/*
 *  Ejemplo 3: listarClientes es la funcion mas compleja que voy realizar, no recibe parametros
 *  y retorna un listado de clientes. Utiliza varios metodos del ejemplo 2.
 */
 class Cliente {
  var $id;
  var $nombre;
 var $apellido;
 var $cuit;
}
class ClienteDAO {
 /**
  * getCliente($id) : Cliente
  * Esta funcion deberia implementarse con una conexion a una base de datos
  * y obtener la informacion de la base directamente
  */
 function getCliente($id) {
  $obj = new Cliente();
  if ($id==1) {
   $obj->id = 1;
   $obj->nombre = 'Blas';
   $obj->apellido = 'Pascal';
   $obj->cuit = '11-11111111-1';
  }
  if ($id==2) {
   $obj->id = 2;
   $obj->nombre = 'Isaac';
   $obj->apellido = 'Newton';
   $obj->cuit = '22-22222222-2';
  }  
  return $obj;
 }
 
 /**
  * getList : Array
  * Esta funcion retorna un listado de todos los clientes que estan en el sistema.
  * @return 
  */
 function getList() {
  $rta = array();
  $rta[0] = $this->getCliente(1);
  $rta[1] = $this->getCliente(2);
  return $rta;
 }
}

$server->wsdl->addComplexType('Cliente',
 'complexType',
 'struct',
 'all',
 '',
 array(
 'id' => array('name' => 'id', 'type' => 'xsd:int'),
 'nombre' => array('name' => 'nombre', 'type' => 'xsd:string'),
 'apellido' => array('name' => 'apellido', 'type' => 'xsd:string'),
 'cuit' => array('name' => 'CUIT', 'type' => 'xsd:string')
 )
);

$server->wsdl->addComplexType('listadoClientes',
 'complexType',
 'array',
 '',
 '',
 array (array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'tns:Cliente[]'))
);
$server->register('listarClientes', // Nombre de la funcion
       array(), // Parametros de entrada
       array('return' => 'tns:listadoClientes'), // Parametros de salida
       $miURL
     );
function listarClientes() {
 $dao = new ClienteDAO();
 $listado = $dao->getList();
 $objSoporte = new SoporteWS();
 $respuesta = $objSoporte->convertirAVectorParaWS($listado);      
 return new soapval('return', 'tns:listadoClientes', $respuesta);
}


$server->service($HTTP_RAW_POST_DATA);
?>
Existen una lista de modificaciones que voy a ir detallando en los siguientes puntos.

Agregar una función en el DAO para que retorne una lista

Como mencione anteriormente en esta oportunidad debemos retornar un listado de clientes, por eso debemos modificar la clase ClienteDAO agregando un nuevo método getList, el cual retorna una lista con todos los clientes.
        function getList() {
  $rta = array();
  $rta[0] = $this->getCliente(1);
  $rta[1] = $this->getCliente(2);
  return $rta;
 }
La clase ObjetoDAO agrega un nuevo método llamado getList(), el cual retorna una lista de todos los clientes que tenemos en el sistema. Al igual que en el ejemplo 2, cuando implementemos este método en un servidor productivo, tendrá una lógica de acceso a datos para obtener la información de alguna fuente de datos. Por ejemplo, si la fuente de datos fuera una base de datos, deberiamos ejecutar una sentencia SQL similar a "select * from Cliente" y luego convertir los resultados en un listado de Clientes.

Definimos la estructura retornada

Debemos definir el nuevo tipo de datos que vamos a retornar, en este caso debemos retornar una lista de clientes, la cual esta definida por la siguiente estructura:
$server->wsdl->addComplexType('listadoClientes',
 'complexType',
 'array',
 '',
 '',
 array (array('ref'=>'SOAP-ENC:arrayType','wsdl:arrayType'=>'tns:Cliente[]'))
);
Como podemos ver en el código anterior, definimos un tipo de datos "listadoClientes" el cual es un array de "Cliente" (el tipo de datos que habíamos definido en el ejemplo 2). Con estas simples lineas estamos indicando que vamos a retornar un listado (vector) y que cada elemento de dicho vector contendrá un Cliente.

Registramos el servicio web a publicar

$server->register('listarClientes', // Nombre de la funcion
       array(), // Parametros de entrada
       array('return' => 'tns:listadoClientes'), // Parametros de salida
       $miURL
     );
Al igual que en los ejemplos anteriores debemos registrar/publiar el servicio web, para ello llamamos a el método register del server. Definimos que el servicio web expuesto llamará a la función "listarClientes" y que la misma retornará un tipo de datos tns:listadoClientes (el tipo de datos definido en el punto anterior).

Implementación de la función

Debemos implementar la función que será llamada cuando el cliente del webservice haga uso del mismo. En este caso será implementado por la función listarClientes().
function listarClientes() {
 $dao = new ClienteDAO();
 $listado = $dao->getList();
 $objSoporte = new SoporteWS();
 $respuesta = $objSoporte->convertirAVectorParaWS($listado);      
 return new soapval('return', 'tns:listadoClientes', $respuesta);
}
Esta función es muy similar a la del ejemplo 2, pero en este caso hacemos uso de un objeto auxiliar (que he creado y el código del mismo esta disponible para descargar al final del artículo) el cual se encarga de la conversión del vector de objetos, en un vector de vector. La conversión es realizada por el método convertirAVectorParaWS del objeto $objSoporte (el cual es de la clase SoporteWS). Al igual que en los ejemplos anteriores, debemos convertir la respuesta en un tipo de datos predefinido, en este caso es el que creamos recientemente (tns:listadoClientes).
Como se puede ver, una vez pasado el ejemplo 1, los pasos son más repetitivos, hemos incorporado algunos objetos de soporte para mantener el código limpio, e intentado hacer el ejemplo cada vez un poco más cercano al mundo real. 

Módulo Cliente

El módulo cliente es el mismo que el del ejemplo 2, simplemente modificamos el nombre del script del servidor y el nombre de la función a llamar. En este caso el script del servidor tiene como nombre "nusoap_server_ej3.php" y la función que vamos a hacer uso en el webservice es "listarClientes"
<?php
require_once('nusoap/lib/nusoap.php');
// Crear un cliente apuntando al script del servidor (Creado con WSDL)
$serverURL = 'http://pruebas.orlandobrea.com.ar';
$serverScript = 'nusoap_server_ej3.php';
$metodoALlamar = 'listarClientes';

$cliente = new nusoap_client("$serverURL/$serverScript?wsdl", 'wsdl');
// Se pudo conectar?
$error = $cliente->getError();
if ($error) {
 echo '<pre style="color: red">' . $error . '</pre>';
 echo '<p style="color:red;'>htmlspecialchars($cliente->getDebug(), ENT_QUOTES).'</p>';
 die();
}


// 2. Llamar a la funcion listadoClientes del servidor
$result = $cliente->call(
    $metodoALlamar,                     // Funcion a llamar
    array(),    // Parametros pasados a la funcion
    "uri:$serverURL/$serverScript",                   // namespace
    "uri:$serverURL/$serverScript/$metodoALlamar"       // SOAPAction
);
// Verificacion que los parametros estan ok, y si lo estan. mostrar rta.
if ($cliente->fault) {
    echo '<b>Error: ';
    print_r($result);
    echo '</b>';
} else {
    $error = $cliente->getError();
    if ($error) {
        echo '<b style="color: red">Error: ' . $error . '</b>';
    } else {
     echo 'Respuesta: ';
  print_r($result);
    }
}
?>

Conclusión

Una vez que vamos avanzando en los ejemplos de WebServices podemos ver la complejidad de los mismos se puede mantener en un nivel similar (ayudandonos de algunos objetos de soporte). Como ya se habrán dado cuenta, no voy a describir la implementación de la clase SoporteWS ya que el código de la misma es código PHP standard, y escapa a los fines del ejemplo. Para simplificar lo que hace esta clase es convertir un objeto en un vector, y un listado de objetos, en un vector de vector. En el próximo ejemplo voy a hacer un ejemplo del mundo real, en el cual se listan los usuarios y al hacer click sobre un enlace, podemos ver todos los datos del mismo. El código de este ejemplo se puede descargar aquí.
Espero que los ejemplos hayan podido introducir a todas aquellas personas que estan realizando webservices, o estan planeando realizar webservices con PHP y NuSOAP.  

AGREGADO: Enlace para descargar el ejemplo completo

5 nov 2009

Regalo de Google - Crédito para probar AdWords

En el día de ayer recibí un e-mail de google que me ofrecía $190.- de crédito para comenzar a utilizar AdWords (seguramente muchos recibieron esta promoción). Al que no lo recibió le comento de donde se originó el e-mail y porque me llego.

Hace un tiempo (varios años que utilizo Google Analytics para uno de mis sitios web) y realmente nunca me termine de inscribir en AdWords, quizás porque generalmente los sitios que manejo tienen un buen posicionamiento (obviamente, cuando les presto atención). Pero, volviendo al tema, al estar inscripto en Google Analytics, y no en AdWords, Google lanzó una campaña de promoción de AdWords, en la cual dan un crédito de ARS $190.- para aquellos que se quieran iniciar en AdWords.

Para acceder a esto, simplemente hay que pegar el código que viene en el e-mail de Google, en el campo de código de promoción cuando uno inicia la cuenta de AdWords. Y ya tenemos nuestra cuenta de AdWords creada (el monto total del cupón de Google es de $205, pero como Google AdWords cobra un gasto por inicio de la cuenta, terminan quedando $190.-).

Es importante tener en cuenta que si nosotros asociamos nuestra tarjeta de crédito, automáticamente deberíamos disponer de dicho saldo para operar. En cambio, si seleccionamos como medio de pago Banelco / PagoMisCuentas se debe realizar un deposito de $50.- como mínimo para comenzar a utilizar la cuenta. Yo lo veo bien, y en caso que AdWords sea tan bueno como algunos dicen, es bueno invertir solo $50.- para tener de crédito $240.-

Es cuestión de arriesgarse, y ver que pasa. Tantas veces invertimos en gustos más caros para que terminen tirados por algún rincón de nuestra casa, porque no invertir $50.- con la posibilidad de generar más tráfico y ventas en nuestro sitio web.

Otro punto importante que es importante destacar para los usuario de Google AdWords de Argentina, es que ahora tiene mayor cantidad de medios de pago (antes mencione algo), por ejemplo, permite pagar con tarjeta de crédito (que no es ninguna novedad), pero también incorporó la posibilidad de hacer los pagos a través de la red Banelco de cajeros automáticos (ATM), y del sitio web de PagoMisCuentas.

Bueno, luego les comentare que tal me fué con esta prueba que estoy realizando, gracias al crédito de Google. A todos aquellos que le hayan llegado el cupón, les recomiendo que lo prueben, es una muy buena oportunidad para hacer algunas pruebas.

Buscar la página de Google AdWords de tu país

26 sept 2009

WebServices con NuSOAP en PHP - Ejemplo 2

En este segundo ejemplo de WebServices con PHP utilizando NuSOAP como biblioteca, voy a mostrar un ejemplo un poco más complejo que el del post anterior (WebServices con NuSOAP en PHP - Ejemplo 1). En este nuevo ejemplo voy a añadir un objeto "Cliente" en el servidor, el cual va a ser devuelto al consumidor/cliente del webservice (previa conversión del objeto a un vector). Para que quede más en claro, comenzare por los ejemplos del servidor y el cliente.

El servidor

Al ser un ejemplo un poco más complejo decidí agregar algunos comentarios más para que el código sea un poco más legible. Igualmente luego del código comentaré algunos fragmentos de código más en detalle.
 

<?php
// Importar la biblioteca NuSOAP
require_once('nusoap/lib/nusoap.php');
$miURL = 'http://pruebas.orlandobrea.com.ar/nusoap';
$server = new soap_server();
$server->configureWSDL('ws_orlando', $miURL);
$server->wsdl->schemaTargetNamespace=$miURL;

/*
* Ejemplo 2: getCliente es una funcion mas compleja que recibe un id y retorna el cliente
* que le corresponde (solo retorna 2 clientes). Tener en cuenta que las respuestas del
* WebService son un Array (vector) y no un objeto propiamente dicho. Si deseamos recuperar
* el objeto del lado del cliente, lo debemos convertir de vector a objeto. En el ejemplo 3
* se ampliara sobre este tipo de operaciones.
*/
// El objeto que voy a enviar al cliente como respuesta
class Cliente {
var $id;
var $nombre;
var $apellido;
var $cuit;
}
// Un objeto de acceso a datos (DAO - Data Access Object) que es el encargado de
// administrar los objetos almacenados (en este caso todos los valores estan
// prefijados, pero en un ejemplo real se podrian obtener de una base de datos)
class ClienteDAO {
/**
* getCliente($id) : Cliente
* Esta funcion deberia implementarse con una conexion a una base de datos
* y obtener la informacion de la base directamente
*/
function getCliente($id) {
$obj = new Cliente();
if ($id==1) {
$obj->id = 1;
$obj->nombre = 'Blas';
$obj->apellido = 'Pascal';
$obj->cuit = '11-11111111-1';
}
if ($id==2) {
$obj->id = 1;
$obj->nombre = 'Isaac';
$obj->apellido = 'Newton';
$obj->cuit = '22-22222222-2';
}
return $obj;
}
}
// Creo la estructura en la cual voya convertir al objeto Cliente, para enviarlo al
// consumidor del WebService (En este caso contiene un vector con id, nombre, apellido
// y cuit)
$server->wsdl->addComplexType('Cliente',
'complexType',
'struct',
'all',
'',
array(
'id' => array('name' => 'id', 'type' => 'xsd:int'),
'nombre' => array('name' => 'nombre', 'type' => 'xsd:string'),
'apellido' => array('name' => 'apellido', 'type' => 'xsd:string'),
'cuit' => array('name' => 'CUIT', 'type' => 'xsd:string')
)
);
// Registro la funcion que se expone en el webservice, la que puede consumir el cliente,
// e indico a que funcion PHP se debe llamar cuando el cliente invoque el webservice
// (getCliente)
$server->register('getCliente', // Nombre de la funcion
array('id' => 'xsd:int'), // Parametros de entrada
array('return' => 'tns:Cliente'), // Parametros de salida
$miURL
);
// Funcion que es llamada por el WebService de NuSOAP cuando el cliente intenta consumir
// el servicio web expuesto
function getCliente($id) {
$dao = new ClienteDAO();
$cliente = $dao->getCliente($id);
// Convierto el objeto en un vector, con una key por cada propiedad del objeto
$respuesta = array('id'=> $cliente-id,
'nombre' => $cliente->nombre,
'apellido' => $cliente->apellido,
'cuit' => $cliente->cuit
);
// Indico que el parametro de respuesta es del tipo tns:Cliente, y cual es el vector
// que contiene dicha estructura
return new soapval('return', 'tns:Cliente', $respuesta);
}

$server->service($HTTP_RAW_POST_DATA);
?>

En el códido de este nuevo ejemplo, existen algunas diferencias con respecto al del ejemplo1, por eso voy a intentar detallar cada una de ellas con un poco de detalle, para poder explicar de que se trata cada una de las nuevas incorporaciones.

Creamos un objeto Cliente

En este nuevo módulo servidor utilizamos una clase llamada "Cliente" que es la que luego de ser convertida, será devuelta al cliente/consumidor del WebService. Decidí crear una clase, para hacer el ejemplo un poco más acorde a lo que nos encontraremos en la vida cotidiana, es decir, hoy en día estamos muy acostumbrados a trabajar con objetos, y que toda la información que tengamos disponibles en nuestros sistemas se encuentren representadas por objetos. Es por eso, que comence  incorporar los objetos al ejemplo. La definición de la clase es la siguiente:

class Cliente {
var $id;
var $nombre;
var $apellido;
var $cuit;
}

Es un objeto muy simple, el cual no tiene asociaciones con otros objetos, simplemente tiene 4 atributos:

  • id
  • nombre
  • apellido
  • cuit

Si bien el objeto es muy simple, nos servirá para poder comenzar a ver cuales son las implicancias del mismo y como debemos convertirlo para luego retornarlo el cliente del webservice.

Creamos un objeto ClienteDAO

Siguiendo con la esta nueva meta de acercar el ejemplo a la vida real, incorporé un objeto DAO (Data Access Object). Para aquellos que no conocen o no están acostumbrados a usar un DAO, voy a intentar definirlo con unas pocas palabras. Cuando creamos aplicaciones multicapa, algo muy común hoy en día, es normal que una de las capas se llame DAO, que podríamos traducir como Capa de Acceso a Datos. Esta capa de acceso a datos, es la encargada de manejar los datos de la aplicación, por ejemplo la que se encarga de leer, guardar y borrar datos de un origen de datos, como podría ser una base de datos, un archivo XML, u otro webservice. Esta capa nos permite abstraer toda la lógica de acceso a datos, para que, si el día de mañana decidimos cambiar de motor de base de datos, o de origen de datos, no tengamos que modificar todas las demás partes del código, solamente cambiamos las clases de esta capa. Generalmente se utiliza un objeto DAO por cada objeto del dominio que queremos guardar/modificar/borrar (existen formas de agrupar en un único objeto las operaciones sobre varios objetos del dominio, pero es dependiente del lenguaje, y prefiero no ahondar en ello para no complicar el ejemplo).

Ya explicado, muy brevemente, que es un DAO vamos a la definición de la clase ClienteDAO:

class ClienteDAO {
/**
* getCliente($id) : Cliente
* Esta funcion deberia implementarse con una conexion a una base de datos
* y obtener la informacion de la base directamente
*/
public function getCliente($id) {
$obj = new Cliente();
if ($id==1) {
$obj->id = 1;
$obj->nombre = 'Blas';
$obj->apellido = 'Pascal';
$obj->cuit = '11-11111111-1';
}
if ($id==2) {
$obj->id = 1;
$obj->nombre = 'Isaac';
$obj->apellido = 'Newton';
$obj->cuit = '22-22222222-2';
}
return $obj;
}
}

Simplemente definimos un método, getCliente, para el objeto que crearemos. Para mantener el ejemplo sencillo, la información retornada por el mismo esta pre-fijada, es decir, no es tomada desde una base de datos, u otra fuente, como si sería en una aplicación del mundo real. Si este método lo implementaramos en una aplicación real, ejecutariamos una sentencia SQL similar a "select * from Cliente where id=".$id y luego convertiriamos la respuesta en un objeto Cliente que es el que retornamos.

Dado que es un ejemplo sin conexión con un origen de datos, esta simple función puede retornar solo 2 objetos clientes, uno para cuando se le pasa como parámetro 1, y otro para cuando se pasa como parámetro 2. En caso de pasar cualquier otro valor como parámetro la función retornará un objeto Cliente sin inicializar sus atributos.

Definimos el tipo de datos devuelto por el WebService

A diferencia del ejemplo 1, en el cual nuestro WebService solo retornaba un String (xsd:string), en esta oportunidad nuestro WebService, retornará un objeto (representado en un vector). Pero como estamos retornando un valor complejo, es decir, no es un string, o int, u otro tipo que ya este predefinido, debemos definirlo nosotros, para ello usamos el siguiente ceodigo:


En el código, estamos informandole a nuestro objeto $server, que utilizaremos un tipo de datos propio, o tipo complejo (este tipo de datos complejo se reflejará en nuestro WSDL del WebService). Los parámetros que más nos interesan para la función "addComplexType" son el primero, y el último. 

El primer parámetro define cual es el nombre que le asignamos a este tipo de datos complejo, en este caso "Cliente".

El último parámetro define como esta compuesto este tipo de datos complejo. Como podemos ver en el ejemplo, el tipo de datos se define como un array (vector) el cual esta compuesto por varios elementos (id, nombre, apellido, cuit), y cada uno de dichos elementos debe tener un vector que contenga "name" y "type" es decir la definición para cada tipo de datos que compone este tipo complejo. Lo que hacemos, no es más que definir un tipo de datos complejo, compuesto por diferentes tipos de datos simples (con simple, me refiero a aquellos que son los estandares) y/o otros tipos de datos complejos que ya hayan sido definidos. Es similar a la definición de una estructura de datos, u objeto. Debemos tener en cuenta que los tipos de datos simples tienen el prefijo xsd (recordarlo para incorporarlo a cada tipo que estamos definiendo).

Registración de la función a exponer

Al igual que en el ejemplo 1, debemos exponer cuales funciones deseamos publicar en nuestro WebService, para ello llamamos al método "register" de nuestro objeto $server, como podemos ver en el siguiente código:

$server->register('getCliente', // Nombre de la funcion
array('id' => 'xsd:int'), // Parametros de entrada
array('return' => 'tns:Cliente'), // Parametros de salida
$miURL
);

La registración de la función expuesta, es muy similar al ejemplo 1, la única diferencia es que en vez de retornar un tipo de datos xsd:string, retornamos un tipo de datos complejo tns:Cliente. Este tipo de datos, es el que definimos en el punto anterior. Con los últimos 2 puntos le estamos indicando a NuSOAP que vamos a retornar un tipo de datos complejo, el cual tiene la estructura definida en tns:Cliente (estructura definida en el punto anterior). 

Función que retorna el cliente

Al igual que en el ejemplo anterior tenemos una función que es la encargada de procesar el pedido y retornar la respuesta. En este caso dicha función se llama getCliente y es la siguiente:

function getCliente($id) {
$dao = new ClienteDAO();
$cliente = $dao->getCliente($id);
// Convierto el objeto en un vector, con una key por cada propiedad del objeto
$respuesta = array(
'id'=> $cliente->id,
'nombre' => $cliente->nombre,
'apellido' => $cliente->apellido,
'cuit' => $cliente->cuit
);
// Indico que el parametro de respuesta es del tipo tns:Cliente, y cual es el vector
// que contiene dicha estructura
return new soapval('return', 'tns:Cliente', $respuesta);
}

Al estar utilizando objetos para obtener los datos que deseamos retornar, tenemos algunos pasos más en al función que en el ejemplo anterior. 

  • Definimos en objeto $dato que es del tipo ClienteDAO (la capa de acceso a datos).
  • Obtenemos el cliente con el $id pasado como parámetro, a través del objeto DAO que creamos en el primer paso.
  • Convertimos el objeto cliente en un vector para luego poder retornarlo (usamos como key, el nombre de cada uno de los atributos del objeto).
  • Retornamos el vector, informando que el mismo es del tipo tns:Cliente (es decir, le pedimos a NuSOAP que nos cree un tns:Cliente a partir del vector pasado como parámetro.

¿Como creo el mapeo entre el objeto y el vector?

Para alcanzar este objetivo, cada uno puede tener sus preferencias, yo utilizó una correspondencia 1 a 1, entre el nombre del atributo y la key del vector. Ejemplo:

class Cliente { $vector = array(
var $id; --------> 'id' => '',
var $nombre; --------> 'nombre' => '',
var $cuit; --------> 'cuit' => ''
} );

Como vemos en el ejemplo, la propiedad id del objeto Cliente, se corresponde con la key 'id' del vector $vector. Cuando el objeto es copiado al vector, al acceder a $cliente->id; PHP no da el mismo valor que $vector['id'];

Cliente

El cliente no tiene mayores modificaciones que el del ejemplo 1, simplemente modifica el nombre del script del servidor, y la función a la cual se llama en el mismo.

<?php
require_once('nusoap/lib/nusoap.php');
// Crear un cliente apuntando al script del servidor (Creado con WSDL)
$serverURL = 'http://pruebas.orlandobrea.com.ar';
$serverScript = 'nusoap_server_ej2.php';
$metodoALlamar = 'getCliente';

$cliente = new nusoap_client("$serverURL/$serverScript?wsdl", 'wsdl');
// Se pudo conectar?
$error = $cliente->getError();
if ($error) {
echo '<pre style="color: red">' . $error . '</pre>';
echo '<p style="color:red;'>htmlspecialchars($cliente->getDebug(), ENT_QUOTES).'</p>';
die();
}


// 2. Llamar a la funcion getCliente del servidor
$result = $cliente->call(
"$metodoALlamar", // Funcion a llamar
array('id' => '1'), // Parametros pasados a la funcion
"uri:$serverURL/$serverScript", // namespace
"uri:$serverURL/$serverScript/$metodoALlamar" // SOAPAction
);
// Verificacion que los parametros estan ok, y si lo estan. mostrar rta.
if ($cliente->fault) {
echo '<b>Error: ';
print_r($result);
echo '</b>';
} else {
$error = $cliente->getError();
if ($error) {
echo '<b style="color: red">Error: ' . $error . '</b>';
} else {
echo 'Respuesta: ';
print_r($result);
}
}
?>

El cliente es muy sencillo, ya que simplemente muestra el contenido de la respuesta del servidor. En un ejemplo del mundo real, el vector que nos devuelve el servidor, lo deberíamos convertir a un objeto cliente (haciendo el mapeo inverso. Antes pasamos del objeto a un vector, y ahora deberíamos pasar del vector a un objeto). En el ejemplo 4, voy a hacer el cliente un poco más complejo, convirtiendo del vector a un objeto, y luego operando con el objeto.

Conclusión

En este ejemplo el servidor fué el que recibió modificaciones, para poder comenzar a operar con objetos, pero el cliente lo mantuve igual de simple que en el ejemplo anterior. También podés descargar el archivo comprimido con el ejemplo. Como vemos a medida que vamos aproximando nuestro ejemplo a la vida real, el mismo se hace un poco más complejo y debemos utilizar diferentes conocimientos que a veces escapan al del WebService en si. 

20 sept 2009

MAC OS X - Reemplazar una carpeta borra la anterior

Todos aquellos que comenzamos a trabajar con OS X en el último tiempo, en algún momento vamos a tener que copiar una carpeta sobre otra, y a diferencia de otros sistemas operativos, OS X realmente reemplaza la anterior por la nueva carpeta.
Cuando arrastramos una carpeta y dicha carpeta ya existe, el sistema operativo OS X nos pregunta si deseamos reemplazar la carpeta, yo (como muchas otras personas) entendemos por reeemplazar el mantener el solo reemplazar los archivos que ya existen por los nuevos, y no eliminar la carpeta anterior, para reemplazarla por la nueva que estamos copiando.
No recuerdo si esto era así en OS 8 y OS 9, ya hace tanto tiempo que no los uso, pero no recuerdo haber tenido este inconveniente.

Tome algunas capturas de pantallas, para poder entender mejor cual es el inconveniente, dicen que una imagen vale más que mil palabras, en una imagen no pude describir todo el proceso, entonces, tendremos que conformarnos con varias imagenes.

Paso 1

Primero cree una carpeta para el ejemplo, la cual se llama Documentos.

Paso 2

Esta es la carpeta que deseamos copiar en la anterior.

Paso 3

Arrastramos la carpeta nueva, en la carpeta vieja. Si estamos acostumbrados a otros sistemas operativos, solo debemos arrastrar la carpeta nueva a la carpeta que deseamos reemplazar.

Paso 4

El sistema operativo OS X nos solicitá que confirmemeos que deseamos reemplazar la carpeta destino, por la nueva carpeta. Uno tiende a pensar (al menos yo) que lo que va a hacer es reemplazar todos los archivos que se encuentran en la carpeta destino, y que existen en la carpeta origen.

Paso 5

En esta imagen vemos como quedo la carpeta destino. Como podemos ver, los archivos creados anteriormente ya no existen. MAC OS-X eliminó los archivos anteriores, y los reemplazo por los archivos de la carpeta origen.

¿Que me pasó?

Dado que yo no sabía de esta "sutileza" de OS X, perdí toda la carpeta de instalación de Drupal. Tenía que actualizar Drupal a una nueva versión, entonces simplemente hice drag and drop desde la nueva versión que descargue de Drupal, en el directorio del sitio que estaba desarrollando. Como elimina los archivos y carpetas anteriores, perdí todos lo módulos que tenía instalados, y algunos en los cuales estaba desarrollando.

Debo ser sincero, que cuando me paso esto, no dije "Que bueno que es el MAC OS-X" sino todo lo contrario. Desde el punto de vista de usabilidad me parece un gran error, que me extraña de la gente de Apple, que siempre se caracteriza por facilitarle la vida al usuario (en este caso, no lo lograron).

Alternativa para copiar sin borrar

En caso que deseen copiar una carpeta en otra, sin perder los datos de la carpeta anterior, lo que deben hacer es ir a la linea de comandos y escribir la siguiente sentencia:

cp -R <directorio origen> <directorio destino>

Espero que sea de utilidad para prevenir a alguien de perder algún dato. En caso que ya sea tarde, te recomiendo que busques alguna herramienta de recuperación de datos (a mi no me funcionó, pero a algunas personas parece que sí).


16 sept 2009

Gran crecimiento de Lorena en Brilla con MaryKay

Estoy sorprendido por la capacidad de emprendimiento que tiene Lorena, podemos ver en Brilla con MaryKay como en solo unas pocas semanas de haber comenzado su emprendimiento como consultora de belleza independiente ya tiene su sitio web, sigue cargando información, y por sobre todas las cosas, tiene promociones muy interesantes durante el mes de septiembre.

Ahh, también ya esta cargando las promociones que se ven presentando en Twitter, la podes seguir en @BrillaConMK.

Espero que siga progresando y trabajando tanto como hasta ahora, seguramente muy pronto llegará a ser directora. Es un claro ejemplo que si se quieren realizar las cosas, se pueden realizar, solo es cuestión de hacerlas con ganas.

14 sept 2009

Serie de TV "Shark Tank" - Emprendedores vs Inversores

Hoy descubrí una serie de TV gracias a Twitter, una de las personas que sigo en dicha red @StartupPro publico un tweet de un show de televisión llamado "Shark Tank" (que sería "Tanque de tiburones"). A pesar de su nombre, no tiene nada que ver con los tiburones reales, sino con un grupo de 5 inversionistas que escuchan a emprendedores vender sus ideas.

El show consiste en que hay 5 inversores dispuestos a escuchar propuestas de los emprendedores que asisten al show. Cada emprendedor tiene un tiempo reducido para presentar sus ideas. Luego de que el emprendedor presenta su idea, los inversores deciden si les parece que es una buena idea como para invertir en ella, y las capacidades del emprendedor. Al igual que en la vida real, evalúan no solo la idea y si económicamente les resulta conveniente, sino que también evalúan que tan preparado esta el emprendedor para llevarla a cabo. Como sabemos, es un conjunto, la idea debe ser económicamente redituable (y financiaramente) así como también la persona que la llevará a la práctica debe estar capacitada y dispuesta a dar todo de ella para llegar a la meta.

El comportamiento es muy parecido a el de los inversores ángeles o angel inverstors, en el cual el emprendimiento aún no esta en funcionamiento o es muy reciente, siendo difícil acudir a entidades bancarias. Por tal motivo, y como generalmente pasa en estos tipos de inversiones, se busca obtener la mayor participación posible en el emprendimiento por parte del inversor. Es decir, el inversor quiere tener la mayor participación en las decisiones posibles, ya que al invertir una suma importante de dinero, y teniendo garantías nulas o casi nulas, se debe asegurar que la persona haga lo mejor para cumplir con el objetivo, y en caso que se este desviando o piense que la mejor alternativa puede ser otra, poder modificar el rumbo del emprendimiento.

Este tipos de inversiones son duras para ambas partes, el inversor arriesga mucho dinero, sin una garantía real, mientras que el emprendedor, da "todo" su tiempo intentando cubrir las expectativas planteadas.

Volviendo al show, si bien esta un poco preparado para la TV, es bastante duro, pero esta muy bueno para poder ver cual es la visión de cada una de las partes. Como cada persona defiende sus intereses y hasta que punto cada parte esta dispuesta a ceder. Cual es el limite de cada parte. También es interesante poder ver las diferentes ideas que tienen las personas, algunas muy raras, otras que no parecen negocio (no me animo a decir que no lo son, ya que hasta no llevarlo a la práctica muchas veces nos pueden sorprender), unas interesantes, otras no tanto, en fin hay de todo.

Para todos aquellos que deseen conocer más sobre el show, pueden visitar la página del mismo en Shark Tank en ABC, si no estas en Estados Unidos, no vas a poder ver el show, pero por suerte, en YouTube existen varios episodios. Sino también podes buscar en google shark tank.

8 sept 2009

Emprendimientos - 10 puntos para verificar la realidad

Este post es una traduccion del post de Martin Zwilling (Entrepreneurs: Ten-Point Reality Check). El post original en ingles lo podes encontrar en http://blog.startupprofessionals.com/2009/09/entrepreneurs-ten-point-reality-check.html. Este post se refiere al libro de Guy Kawasaki "Reality Check: The Irreleverent Guide to Outsmarting, Outmanaging, and Outmarketing Your Competition".

Quiero agradecer especialmente a Martin por haberme permitido realizar la traduccion de su post.

10 puntos para verificar la realidad en emprendimientos

Estos son una serie de puntos a verificar si ya has sido mordido por el bug del startup, o si ya has comenzado tu emprendimiento. Tambien es genial si has estado alli por un tiempo, y necesitas volver a la tierra. El libro contiene 474 paginas, pero hay unos 10 puntos del libro que tocaron algo en mi:

  1. La realidad del comienzo. No va a mejorar - ya esta. Las personas iniciadoras son como los monasterios medievales: siempre convencidos que el paraiso esta justo adelante o que las cosas recientemente han empeorado.
  2. La realidad de incrementar el dinero. La analogia del mundo real mas cercana a incrementar ingresos, son las citas rapidas. Es verdad: en 5 minutos, la persona persona decide si esta interesada en vos, como en los bares o bailes. No esta bien, ni es justo, pero es la realidad.
  3. La realidad de planear y ejecutar. Si pensas que incrementar el dinero no es la parte dificil, estas por sorprenderte. El incrementar el dienro, es la parte fácil y divertida. El trabajo real comienza cuando debes entregar los resultados prometidos.
  4. La realidad de la innovación. Muchas personas que la innovación es fácil: te sentás con tus amigos e ideas mágicas ingresan en tu cabeza. O tus clientes te dicen lo que necesitan. Segui soñando. La innovación es dura, es un proceso sucio que no tiene atajos.
  5. La realidad del marketins. Todo el mundo desea hacer las cosas divertidas: relacionarse con personas hermosas, y crear campañas de marketing. Mas precisamente, el marketing es el proceso de convencer a las personas que necesitan tu producto. Eso no es tán fácil, ni divertido.
  6. La realidad de comunicar. El emprendedorismo es una actividad enfocada hacia afuera. Requiere que te comuniques con otros utilizando todas las formas modernas. Cada forma es una habilidad que debes dominar. Todo esto lleva leer este libro y 20 años de práctica.
  7. La realidad de competir. Si no estas compitiendo con otros por un largo tiempo, puede significar que estas intentando satisfacer un mercado que en realidad no existe.
  8. La realidad de tomar y despedir. Estas son artes oscuras para la mayoría de las personas. Pocas personas están entrenadas para cualquiera, y muchos dependen de sus agallas. Piensan que no cometerán errores en la contratación, entonces nunca tendrán que despedir a nadie. Es incorrecto, y los errores lastiman a las personas y a vos.
  9. La realidad del trabajo. Al comienzo, startups (inicios) son como una hoja de papel en blanco: solo oportunidades y en la parte superior una chance de crear significado y cambiar al mundo. Luego la realidad del trabajo comienza. Crear un éxito es difícil, muy difícil realmente.
  10. La realidad de hacer el bien. Al final de nuestras vidas, sos medido no por la cantidad de dinero que has hecho, sino porque tanto has hecho de este mundo un lugar mejor. Los emprendedores exitosos generalmente cambian a emprendimientos sin fines de lucro y sociales para un impacto real.

Conclusión

Ahora vuelvo a mi opinión y el porque decidí levantar la información de otro post. Me pareció muy bien explicados muchos puntos que todas las personas que hemos comenzado algún emprendimiento, nos hemos enfrentado. Creo que explica bastante bien las diferencias que son ver las cosas de afuera, al verlas desde adentro. Muchas veces cuando uno es joven y no tiene demasiada experiencia, puede cometer el error de querer comenzar un emprendimiento pensando que es todo muy fácil, y luego tener que enfrentarse a la realidad que a veces puede ser muy buena, pero otras puede ser un poco adversa. El emprender es una muy linda experiencia, pero también desgastante por eso debemos estar preparados.

Para finalizar, deseo agregar una frase de Confucio: "Escucho y olvido, veo y recuerdo, hago y aprendo".

6 sept 2009

Nuevo emprendimiento MaryKay de Lorena

Lorena esta comenzando un nuevo emprendimiento como Consultora de Belleza Independiente MaryKay, por eso todos aquellos que se quieran interiorizar en los productos MaryKay, los invito a que visiten su nuevo sitio web Brilla con MaryKay.

Muchos éxitos en este nuevo emprendimiento!!!

WebServices con NuSOAP en PHP - Ejemplo 1


Ya hace un tiempo realice un artículo sobre servicios web con PHP (utilizando NuSOAP), el mismo se puede acceder en WebServices con PHP usando NuSOAP, el mismo ya ha quedado un poco obsoleto debido a que el servidor que alojaba el webservice ya no lo contiene más. Por tal motivo y debido a que uno de los inconvenientes principales cuando uno se esta iniciando en el tema de los webservices con PHP, principalmente con NuSOAP, es encontrar como realizar el módulo servidor. En este primer post, decidí subir un ejemplo sencillo de comunicación entre un módulo servidor que provee expone una función, y un módulo cliente que las consume.

Introducción al ejemplo

No voy a exponer demasiados detalles con respecto a que son los WebServices, para ello pueden acceder al enlace que mencione anteriormente (WebServices con PHP usando NuSOAP). Solamente me limitare a explicar un poco el funcionamiento del mismo
Para el ejemplo, estoy utilizando la siguiente estructura de directorios


Siendo, nusoap_server_ej1.php el servidor de nustro WebService con NuSOAP, y nusoap_client_ej1.php el cliente.

Requerimientos

Los requerimientos para poner en funcionamiento el ejemplo son simplemente NuSOAP y tener algún servidor de sitios web (como puede ser Apache) corriendo PHP. Para todos aquellos que actualmente no tienen un servidor corriendo, pueden descargar XAMPP que es un servidor apache con PHP (también trae otras funcionalidades, pero estas 2 son las que importan para nuestro ejemplo) que solo se descarga, se descomprime, y con solo ejecutar un archivo, se inicia el servidor Apache con PHP en nuestra computadora, sin necesidad de mayores dolores de cabeza (Funciona tanto para Windows, como para OS-X).

Módulo servidor

El servidor de este ejemplo es muy sencillo, tan sencillo como el siguiente código:
<?php
 
// Incorporar la biblioteca nusoap al script, incluyendo nusoap.php (ver imagen de estructura de archivos)
require_once('nusoap/lib/nusoap.php');
// Modificar la siguiente linea con la direccion en la cual se aloja este script
$miURL = 'http://pruebas.orlandobrea.com.ar/nusoap_ej1';
$server = new soap_server();
$server->configureWSDL('ws_orlando', $miURL);
$server->wsdl->schemaTargetNamespace=$miURL;


/*
 * Ejemplo 1: getRespuesta es una funcion sencilla que recibe un parametro y retorna el mismo
 * con un string anexado
 */
$server->register('getRespuesta', // Nombre de la funcion
 array('parametro' => 'xsd:string'), // Parametros de entrada
 array('return' => 'xsd:string'), // Parametros de salida
 $miURL);
function getRespuesta($parametro){
 return new soapval('return', 'xsd:string', 'soy servidor y devuelvo: '.$parametro);
}

// Las siguientes 2 lineas las aporto Ariel Navarrete. Gracias Ariel
if ( !isset( $HTTP_RAW_POST_DATA ) )
    $HTTP_RAW_POST_DATA = file_get_contents( 'php://input' );

$server->service($HTTP_RAW_POST_DATA);
?>
El ejemplo es bastante sencillo, simplemente registra una función que recibe un parámetro y devuelve dicho parámetro con un texto adelante ("soy el servidor y devuelvo: ". El parámetro de entrada a la función es del tipo String, y la función también retorna un String.
Anteriormente mencione que no iba a detallar demasiado en código, ya que como pueden ver el mismo esta comentado, y creo que es bastante entendible.
Como podemos ver en el ejemplo, la complejidad mayor en crear el módulo servidor para un webservice, es crear la estructura de datos del mismo y sus tipos (ver $server->register() en el ejemplo). Si bien el ejemplo es muy sencillo, podemos ver que tanto los datos que el webservice recibe, como los que retorna, deben ser especificados en los tipos de datos predefinidos en XML para crear un Schema (xsd:string, xsd:int, etc.). En los próximos ejemplos que vaya subiendo de webservices con NuSOAP se podrá ver más en detalle algunos tipos de datos, y también como crear estructuras complejas (retornar objetos, o listas). Por el momento solo estamos recibiendo un String (xsd:string y retornamos otro entero (xsd:string).
En el ejemplo se puede ver que la función a la cual el webservice llama para atender la petición, en este caso getRespuesta, debe codificar la respuesta en el tipo de datos esperado. En este caso definimos que la función retornaría un xsd:string, por lo que debemos crear un soapval con el tipo de datos esperado.

¿Como se enlazan los datos recibidos por el servidor con nuestra función?

Cuando definimos los parámetros, tanto de entrada, como de respuesta, a los mismos le asignamos un nombre. Por ejemplo al parámetro de entrada le asignamos el nombre "parametro" (si, no es muy original, pero sirve para entender el ejemplo). Y el parámetro de salida, o retorno, lo llamamos "return". Entonces lo que hará NuSOAP es enlazar el parámetro de entrada a la función getRespuesta cuyo nombre es "parametro", con el valor que tome el "parametro" definido en el webservice. Voy a mostrár graficamente el enlace, para que sea más sencilla su visualización:
 

¿Que pasa si mi función NO recibe parámetros?

Simplemente modificariamos el código de:
$server->register('getRespuesta', // Nombre de la funcion
 array('parametro' => 'xsd:string'), // Parametros de entrada
 array('return' => 'xsd:string'), // Parametros de salida
 $miURL);
al siguiente código:
$server->register('getRespuesta', // Nombre de la funcion
 array(), // Parametros de entrada
 array('return' => 'xsd:string'), // Parametros de salida
 $miURL);
y obviamente a la función que hacemo referencia (getRespuesta) no debería recibir parámetros, por lo que pasaría de:
function getRespuesta($parametro){
a:
function getRespuesta(){

El cliente

Para este ejemplo que estoy mostrando, el cliente tiene un poco más de código que el servidor, para ejemplos un poco más complejos, el servidor comienza a ser un poco más largo, y el cliente mantiene apróximadamente la misma longitud. ¿Por que pasa esto? sencillo, a medida que el ejemplo se hace más complejo, se necesitán funciones más complejas en el servidor y principalmente, definir que los datos que vamos a utilizar también son más complejos. Pero eso lo dejaremos para futuros ejemplos que vaya subiendo al blog. Ahora nos concentraremos en el cliente, cuyo código es el siguiente:
<?php
// Incluimos la biblioteca de NuSOAP (la misma que hemos incluido en el servidor, ver la ruta que le especificamos)
require_once('nusoap/lib/nusoap.php');
// Crear un cliente apuntando al script del servidor (Creado con WSDL) - 
// Las proximas 3 lineas son de configuracion, y debemos asignarlas a nuestros parametros
$serverURL = 'http://pruebas.orlandobrea.com.ar';
$serverScript = 'nusoap_server_ej1.php';
$metodoALlamar = 'getRespuesta';

// Crear un cliente de NuSOAP para el WebService
$cliente = new nusoap_client("$serverURL/$serverScript?wsdl", 'wsdl');
// Se pudo conectar?
$error = $cliente->getError();
if ($error) {
 echo '<pre style="color: red">' . $error  . '</pre>';
 echo '<p style="color:red;'>htmlspecialchars($cliente->getDebug(), ENT_QUOTES).'</p>';
 die();
}

// 1. Llamar a la funcion getRespuesta del servidor
$result = $cliente->call(
 "$metodoALlamar", // Funcion a llamar
 array('parametro' => 'Orlando'), // Parametros pasados a la funcion
 "uri:$serverURL/$serverScript", // namespace
 "uri:$serverURL/$serverScript/$metodoALlamar" // SOAPAction
);
// Verificacion que los parametros estan ok, y si lo estan. mostrar rta.
if ($cliente->fault) {
 echo '<b>Error: ';
 print_r($result);
 echo '</b>';
} else {
 $error = $cliente->getError();
 if ($error) {
 echo '<b style="color: red">Error: ' . $error . '</b>';
 } else {
 echo 'Respuesta: '.$result;
 }
}

?>
Primero voy a hacer un breve resumen de cuales son los pasos que se realizan.
  • Incluír la biblioteca de NuSOAP de PHP.
  • Defino las variables de configuración (lo hice de esta forma para que les sea más sencillo el definir los parámetros para sus propios servicios web).
  • Creo el objeto NuSOAP Cliente (nusoap_client).
  • Verifico que la conexión se haya podido realizar.
  • Llamó al servicio web del servidor (función getRespuesta definida en las variables de configuración).
  • Verifico que la llamada haya sido exitosa, en caso de ser exitosa muestro la respuesta del servidor, y en caso de error, muestro el mensaje de error.
El código del cliente también esta comentado, y definí 3 variables al principio que nos permitirán adaptar el cliente del WebService a nuestras pruebas particulares.
En el cliente no hago un procesamiento de la información recibida desde el servidor de WebServices (NuSOAP server) sino que la muestro directamente por pantalla, cuando estemos trabajando realmente con dicha información debemos realizar un procesamiento de la información recibida antes de utilizarla (el procesamiento puede ser desde algo tan sencillo como mostrar la información en un sitio especifico del website, hasta generar tablas o campos de edición). Las posibilidades de procesamiento son infinitas, y dependen de para que estemos utilizando el WebService, y la información otorgada por el mismo.

Verificación de los scripts

Para comprobar que nuestros scripts estan funcionando, lo que primero recomiendo es primero acceder al script del servidor (http://<direccion de nuestro server>/nusoap_server_ej1.php) desde nuestro navegador, el cual nos debe mostrar una pantalla similar a la siguiente si todo esta correcto (en caso contrario mostrará un típico error PHP por pantalla):

Y si hacemos click sobre el nombre la la función que hemos publicado en nuestro servidor de WebService, nos mostrará algo similar a esto:

Cuando hemos verificado que el servidor esta funcionando, ahora realizaremos la prueba del cliente (http://<direccion de nuestro server>/nusoap_client_ej1.php), y nos mostrará una página similar a la siguiente:

Conclusión

El WebService aquí presentado es un ejemplo básico para todas aquellas personas que estan comenzando con ellos y desean utilizar NuSOAP para crear los mismos y consumirlos.  El código del ejemplo es muy sencillo, pero igualmente decidí publicar un archivo con el ejemplo del cilente y el servidor, para que sea más sencilla la implementación del ejemplo en sus computadoras (Descargar el ejemplo).

5 sept 2009

Ver color hexadecimal HTML

 
Valor hexadecimal del color a ver:

3 sept 2009

Problema con Mail de Apple Templates y Adjuntos

Luego de publicar el post de como crear templates para mail de apple y de un de trabajar con el mismo, me dí cuenta que no permite adjuntar archivos que no sean de imagen. Es decir, cuando estamos utilizando un template para la creación de nuestro e-mail, no podemos agregar archivos adjuntos al mismo (en realidad solo podemos agregar archivos adjuntos de imagen).

Este inconveniente se me presentó al intentar enviar un e-mail a un cliente, al cual le debia adjuntar un archivo, ahí el Mail de Apple me mostró este hermoso mensaje.

Por el momento no he encontrado solución para este inconveniente, aunque sinceramente no he investigado demasiado aún. Espero poder encontrar alguna alternativa para poder seguir utilizando templates, y poder adjuntar archivos.

2 sept 2009

Crear templates para Mail de Apple

Introducción

Una función que para mí es bastante importante en los clientes de e-mail es poder tener la posibilidad de realizar plantillas para nuestros mensajes. Esto nos permite dar un formato más complejo a nuestros e-mails, y que los mismos sean homogéneos. Tener la posibilidad de realizar templates se hace aún más importante en el ámbito laboral, en el cual muchas veces con solo una firma no es suficiente para los e-mails que enviamos.

En esta oportunidad voy a detallar como podemos crear plantillas de e-mail para la aplicación Mail de Apple (OS X).

Los pasos


Crear un template

El primer paso para poder crear un template es comenzar con uno vacio, para ello podes descargar mi template vacio y comenzar a trabajar con el (una vez que lo descarguemos debemos descomprimir el archivo, obtienendo de esta forma un archivo con nombre "obrea Basico.mailstationery").

Abrir el template

Para abrir el template solo debemos hacer CTRL-Click sobre el mismo (o botón derecho del mouse) y seleccionar la opción "Mostrar contenido del paquete"

Se abrirá el Finder dentro del contenido del archivo (los archivos mailstationary en realidad es un paquete con varios archivos dentro). Accedemos a la carpeta "Contents/Resources".

Editar el template

Con el editor de html que estemos acostumbrados a utilizar (yo utilizo Smultron) abrimos el archivo "content.html" el cual tiene un contenido similar a este:

<html>
<head>
        <title>Template creado obrea.blogspot.com</title>
</head>
<body style="margin: 0 0 0 10px;"> 
    
<div style="background-color: #fff; margin: 10px; padding: 10px;">
<div id="encabezado">
  <img src="obreaFondo.jpg" />
</div>

<br/>
<div id="mail-to" contenteditable="true" apple-content-name="to">Reemplazar por un saludo tipico,</div>
<br/>
<div id="mail-body"contenteditable="true" apple-content-name="body">
Reemplazar por un texto predeterminado
</div>
<p contenteditable="true" apple-content-name="bye">Reemplazar por un saludo final tipico,</p>


<div id="pie">
-----------<br/>
Reemplazar por mi nomrbre<br/>
Reemplazar por otros datos que quiera agregar al pie<br/>
</div>
</div>

</body>
</html>

Como podemos ver en el código es todo html puro, por lo tanto es muy fácil poder llevar un diseño que ya tenemos en HTML a un template para Mail de Apple.

Si viste el c&ooacute;digo en profundidad podrás ver que existen algunas propiedades en los tags que no son standares:

 
contenteditable="true"

apple-content-name="un_nombre"

Igualmente sus nombres describen bastante bien cual es su funcionalidad. el código contenteditable="true" le indica a la aplicación Mail que lo que se encuentra envuelto por el tag contenedor puede ser editado. Un punto importante a tener en cuenta, que no mencione anteriormente, es que todo aquello que no se indique explicitamente que puede ser modificado, queda fijo en el template (es decir, todo lo que no indica contenteditable="true" queda fijo como si fuera constante y no puede ser modificado cuando estamos editando el email).

La otra propiedad tiene menos importancia y realmente no es necesaria, pero igualmente la describiré. La propiedad apple-content-name indica el nombre con el cual la aplicación Mail de Apple identifica al contenido del tag. No es indispensable agregarla

En el código de ejemplo, existen 3 áreas editables:

Parte 1

<div id="mail-to" contenteditable="true" apple-content-name="to">Reemplazar por un saludo tipico,</div>

En esta secció podemos ingresar el saludo que tipicamente utilizamos con nuestros destinatarios de e-mail. Por ejemplo: "Hola ," para luego solo tener que ingresar el nombre entre "Hola" y ",".

Parte 2

<div id="mail-body"contenteditable="true" apple-content-name="body">
Reemplazar por un texto predeterminado
</div>

Si tenemos algún tipo de formato de texto que utilicemos siempre en nuestros e=mails, por ejemplo una introducción común podemos agregarlo en esta sección para no tener que escribirla por cada mensaje que enviamos

Parte 3

<p contenteditable="true" apple-content-name="bye">Reemplazar por un saludo final tipico,</p>

En esta última parte podemos indicar cual es el saludo que habitualmente utilizamos. Por ejemplo: "Saludos", "Un abrazo" o cualquier otro texto que utilicemos habitualmente.

Seguimos?

En el template que esta en el sitio, es muy básico, pero sirve para tener una idea de las opciones que nos da esta aplicación. En otro post indicaré como se puede reemplazar una imagen del template con solo hacer un drag and drop sobre la misma, cuando estamos editando el e-mail.

Recomiendo que al momento de estar editando el template, tengamos abierto el archivo content.html en un navegador, por ejemplo Safari, para poder ir viendo como quedan los cambios que vamos realizando

Cada vez que utilicemos una imagen en el template, y la misma no se ecuentre en un sitio web (es decir que se debe env&iactute;r con el e-mail), debemos copiarla en la misma carpeta en la cual se encuentra el archivo content.html (un ejemplo de ello es el archivo obreaFondo.jpg que contiene el banner superior del e-mail).

Una vez que adaptes el template a como más te guste, con tu logo, firma, y todo aquello que quieras agregar, estas en condiciones de seguir con el siguiente paso

Editamos Description.plist

En este archivo debemos ingresar el nombre de todos los archivos de imagen que hemos utilizado en nuestro template. A continuación copio el archivo del template básico:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Folder Name</key>
    <string>obrea Basico.mailstationery</string>
    <key>HTML File</key>
    <string>content.html</string>
    <key>Images</key>
    <array>
        <string>obreaFondo.jpg</string>
    </array>
    <key>Stationery ID</key>
    <string>52CF436E-68DA-4842-B638-1234567</string>
</dict>
</plist>

En este archivo debemos prestar atención a dos secciones, la primera:


    <string>obrea Basico.mailstationery</string>

Que indica cual es el nombre de nuestro archivo de templates, lo debemos modificar por el nombre que le vayamos a poner al archivo contenedor

La segunda sección a la cual debemos prestar atención es


    <key>Images</key>
    <array>
        <string>obreaFondo.jpg</string>
    </array>

Que indica cuales son las imagenes que estamos utilizando en nuestro template, debemos agregar un <string> </string> por cada archivo de imagen que utilicemos en el template. En este caso estamos utilizando solo uno obreFondo.jpg

Asignamos el nombre que se mostrará en Mail

Para ello abrimos el archivo "DisplayName.strings" que se encuentra en la carpeta "English.lproj" y vamos a la línea


"Display Name" = "Template basico";

En esta línea modificamos "Template basico" por el nombre con el cual queremos que aparezca identificado nuestro template dentro de la aplicación Mail

Copiamos el paquete modificado

Una vez que realizamos los pasos anteriores, estamos en condiciones de poder guardar ya nuestro template para comenzar a utilizarlo. Para ello cerramos la ventana del Finder que esta mostrando el contenido del paquete que abrimos (este paso no es necesario, pero es mejor realizarlo para no confundirnos con los archivos).

Vamos al directorio en el cual se encuentra el template que modificamos (el paquete con el template), y modificamos el nombre del mismo por el que hayamos ingresado en Description.plist.

Abrimos una nueva ventana del Finder y accedemos al siguiente directorio "/Library/Application Support/Apple/Mail/Stationery/Apple/Contents/Resources/" luego seleccionamos una carpeta en la cual deseamos incorporar nuestro template, en el ejemplo voy a elegir la carpeta "Announcements", dentro de dicha carpeta accedemos a "Contents/Resources" y dentro de dicho directorio copiamos el archivo que hemos generado a esta carpeta.

Usando el template

Ya estamos en condiciones de poder utilizar el template. Para ello solo debemos crear un nuevo e-mail.

Luego seleccionamos "Mostrar plantillas".

Seleccionamos la categoría que le asignamos al template que hemos realizado.

Seleccionamos el template que generamos (aparecerá el nombre que le hayamos asignado en "Display Name" del archivo "DisplayName.strings").

Aparecerá el template en el cuerpo del mensaje que estamos creando, permitiendonos editar en todas aquellas secciones que hayamos habilitado.

Conclusión

Si bien son varios pasos, es bastante sencilla la modificaci&acue;n y creación de templates para la aplicación Apple Mail.

Hasta el momento es la aplicación de e-mail que mejor integración con templates he encontrado, ya que Outlook, o Mozilla, tienen una buena integración, pero no nos permite con un solo drag and drop cambiar una imagen, o modificar solo partes del template (muy util para no equivocarnos y perder la estética general por borrar una parte que no queriamos)

Te recomiento probar los templates del Mail de Apple, y en caso que aún no hayas probado el Mail de Apple, te propongo que lo hagas, para que puedas ver si también se adapta a tus necesidades