Unite al grupo

Grupos de Google
Suscribirte a webandbeer
Correo electrónico:
Consultar este grupo

martes, 22 de julio de 2008

Coloreando código para blogger o cualquier web

Wordpress tiene una herramienta para colorear código automaticamente, pero para los usuarios de blogger se nos hace algo fastidioso, asi que, que mejor que una herramienta on-line para hacerlo. Soportando muchos leguajes: ActionScript, Ada, Apache, Asm, Asp, Bash, C, C_Mac, Caddcl, cadlisp, Cpp, C# (C Sharp), CSS, D, Delphi, Diff, Div, Eiffiel, Gml, html 4 strict, Java, JavaScript, Lisp, Lua, Matlab, Mpasm, Nsis, Objp, Oobas, Oracle 8, Pascal, Perl, Php, php-brief, Python, Qbasic, Smarty, Sql, Visual Basic, Visual Basic.NET, Vhdl, Visual Fox Pro y Xml.


Aca un ejemplo: El código antes publicado para mostrar una imagen con letras:


  1. /*

  2. Code by Jonathan Ariel Muszkat

  3. muskys@gmail.com

  4. */
  5. // Obtenemos la imagen
  6. $im = imagecreatefromjpeg("imagen2.jpg");
  7. $frase = array('M','E','L','U',' ','Y',' ','J','O','N','Y',' ');
  8. // Iteramos entre las coordenadas X y Y
  9. $j = 0;
  10. $mostrar = "";
  11. for($y=0;$y
  12. for($x=0;$x
  13. // Obtenemos el valor del color
  14. $rgb = imagecolorat($im,$x,$y);
  15. // Convertimos a Hexadecimal
  16. $hex = sprintf("%06X", $rgb);
  17. // Imprimimos la letra con su color
  18. $mostrar .= "".$frase[$j]."";
  19. $j++;
  20. if($j == 12){
  21. $j = 0;
  22. }
  23. }
  24. $mostrar .= "
  25. ";
  26. }
  27. $mostrar .= '';
  28. imagedestroy($im);
  29. die($mostrar);
  30. ?>


Obviamente se puede usar en cualquier web, no solo blogger.

El recurso on-line se puede encontrar aqui: http://www.scourdesign.com/articulos/tutoriales/colorear/

jueves, 17 de julio de 2008

AL FIN UNA BUENA NOTICIA!

de Ajaxian » Front Page de Dion Almaer

Ah the age old IEPNGFix solution to the problem that we had with IE 5.5 / 6.0 not supporting alpha transparency. The first IEPNGFix solved the problem:

This script adds near-native PNG support with alpha opacity to IE 5.5 and 6. Now you can have full translucency and no more ugly grey borders! It requires only one line in your CSS file, and no changes to your website HTML. tags and background images are both supported.

Now we have a new version that adds the ability to use CSS1 compatible background position and repeat.

Pasar imagen a Texto (muy divertido)


/*
Code by Jonathan Ariel Muszkat
muskys@gmail.com
*/
// Obtenemos la imagen
$im = imagecreatefromjpeg("imagen2.jpg");
$frase = array('M','E','L','U',' ','Y',' ','J','O','N','Y',' ');
// Iteramos entre las coordenadas X y Y
$j = 0;
$mostrar = "";
for($y=0;$y for($x=0;$x // Obtenemos el valor del color
$rgb = imagecolorat($im,$x,$y);
// Convertimos a Hexadecimal
$hex = sprintf("%06X", $rgb);
// Imprimimos la letra con su color
$mostrar .= "".$frase[$j]."";
$j++;
if($j == 12){
$j = 0;
}
}
$mostrar .= "
";
}
$mostrar .= '';
imagedestroy($im);
die($mostrar);
?>




Version JPG





/*
Code by Jonathan Ariel Muszkat
muskys@gmail.com
*/
function genera_imagen() {
header("Content-type: image/jpg");
if (file_exists("generada3.jpg")) {
$img = file_get_contents ("generada3.jpg");
$im = imagecreatefromstring ($img);
header('Cache-Control: max-age=864000');
header("Expires: Mon, 26 Jul 2038 05:00:00 GMT");
header("Pragma: ");
header ("Content-Type: image/jpeg");
imagejpeg($im);
imagedestroy($im);
exit;
}

$im = imagecreatefromjpeg("test.jpg");
list ($realWid, $realHei) = getimagesize("test.jpg");
$im2 = imagecreatetruecolor($realWid, $realHei);
imagefill($im2, 0, 0, 0);
$frase = array('M','E','L','U',' ','T','E',' ','A','M','O',' ', 'J', 'O','N','Y');
$font = 'COUR.TTF';
$fontsize = 11;
$j = 0;

for($y=0;$y for($x=0;$x
// Obtenemos el valor del color
$rgb = imagecolorat($im,$x,$y);
$r = ($rgb >> 16) & 0xFF;
$g = ($rgb >> 8) & 0xFF;
$b = $rgb & 0xFF;
$posy = $y + $fontsize;
imagettftext ($im2, $fontsize, 0, $x, $posy, $rgb, $font, $frase[$j]);
$j++;
if($j == count($frase)){
$j = 0;
}
}
}
//$blanco = imagecolorallocate($im2, 255, 255, 255);
//imagettftext ($im2, 20, 0, 0, 20, $blanco, $font, 'Code by Musky'); //Si le queremos poner un copyright
imagejpeg($im2, "generada3.jpg");
imagedestroy($im2);
imagedestroy($im);

}
genera_imagen();/*

Code by Jonathan Ariel Muszkat
muskys@gmail.com
*/


?>

martes, 15 de julio de 2008

Configuración de ISP

Leyendo Linuxeando, me entero en este post que How To Forge sacó una serie de guías para la configuración de un ISP (un servidor completo que ofrezca todos los servicios necesarios para un ISP y alojamiento web: servidor web Apache (con SSL), servidor de correo Postfix con SMTP-AUTH y TLS, servidor DNS con BIND, servidor FTP con Proftpd, servidor MySQL, Dovecot POP3/IMAP, Quota, Firewall, etc.).

Sacaron versiones para distintas distribuciones. Yo estoy esperando la de Slackware.
También hace un tiempo salió un documento de Implementación de servidores con GNU/Linux por Joel Barrios Dueñas.

Con respecto a otros sistemas operativos Unix, también está disponible esta guía para instalar un ISP en FreeBSD, pero por lo que estuve hablando con Cesar a esta guía le faltarían algunas cositas. Estaría bueno que Cesar publique su versión más completa y en castellano.

De más está decir que no pongo las manos en el fuego por NINGUNA de las guías nombradas, sino que esto es meramente para compartir información.

lunes, 14 de julio de 2008

SMF en Solaris

Estuve investigando un poco sobre SMF en Solaris y está bastante interesante, así que comparto lo que aprendí.

Solaris 10 incorpora SMF: Service Management Facility, que básicamente es un daemon que controla los servicios que corren en el sistema operativo. Su idea es reemplazar los scripts de /etc/init.d y /etc/rc.*.d, con una utilidad bastante más robusta y simple de configurar.

A partir de Solaris 10, entonces, vemos que muchos servicios que antes estaban en /etc/init.d ahora desaparecieron de allí y si revisamos el /etc/inittab vemos que una de las primeras cosas que hace es levantar el svc.startd que es el daemon que maneja los servicios de SMF. De hecho, dicen que ahora el boot es bastante más limpito, porque todos los mensajes de los servicios que se inician se van logueando en distintos lugares, y uno termina viendo algo así:

SunOS Release 5.10 Version Generic 64-bit
   Copyright 1983-2004 Sun Microsystems, Inc.  All rights reserved.
   Use is subject to license terms.
   Hostname: demobox
   NIS domain name is testlab.example.com
   checking ufs filesystems

   demobox console login:


En este link hay una Quickstart Guide muy interesante, donde muestra cómo se hacían las cosas en las versiones anteriores de Solaris y cómo deberían hacerse ahora con SMF: http://www.sun.com/bigadmin/content/selfheal/smf-quickstart.jsp

Subir y bajar el apache es tan sencillo como ejecutar los siguientes comandos:

Levantar:     svcadm enable network/http:apache2
Bajar:           svcadm disable network/http:apache2
Reiniciar:     svcadm restart network/http:apache2

Como podrán observar, los servicios se agrupan en unidades más "user-friendly" (o admin-friendly), en vez de ser archivos tirados en directorios (de hecho en Solaris siempre era más molesto que en Linux, porque el archivo debía estar indefectiblemente en /etc/init.d y con hard links en /etc/rc3.d - para el caso de servicios que levantaran en runlevel 3). Además se pueden configurar facilmente variables de entorno y otras cosas locas que se deben inicializar con el servicio.

Por otro lado, al haber un daemon constantemente corriendo, si el servicio no es deshabilitado por un "restarter" habilitado, el servicio se levanta automáticamente:

[root@BOCUNOCDWB04:~]# svcadm enable network/http:apache2
[root@BOCUNOCDWB04:~]# ps -ef |grep httpd
   root 23319     1   3 13:38:59 ?           0:01 /usr/local/apache2/bin/httpd -k start -DSSL
 nobody 23328 23319   0 13:39:02 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
   root 23330 22786   0 13:39:04 pts/2       0:00 grep httpd
 nobody 23327 23319   0 13:39:02 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
   root 23322     1   0 13:39:01 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
 nobody 23326 23319   0 13:39:02 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
 nobody 23325 23319   0 13:39:02 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
 nobody 23324 23319   0 13:39:02 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
[root@BOCUNOCDWB04:~]# pkill httpd
[root@BOCUNOCDWB04:~]# ps -ef |grep httpd
   root 23357     1   0 13:39:22 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
 nobody 23360 23351   0 13:39:22 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
   root 23365 22786   0 13:39:22 pts/2       0:00 grep httpd
   root 23351     1   2 13:39:20 ?           0:01 /usr/local/apache2/bin/httpd -k start -DSSL
 nobody 23359 23351   0 13:39:22 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
 nobody 23361 23351   0 13:39:22 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
 nobody 23362 23351   0 13:39:22 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
 nobody 23363 23351   0 13:39:22 ?           0:00 /usr/local/apache2/bin/httpd -k start -DSSL
[root@BOCUNOCDWB04:~]#

De la misma forma, si hay algún error al levantar el programa o el mismo se muere dejando algún error, el servicio es puesto en estado "maintenance", para poder consultar posteriormente por qué no está corriendo.

[root@BOCUNOCDWB04:~]# svcs -xv network/http:apache2
svc:/network/http:apache2 (Apache 2 HTTP server)
State: maintenance since Mon 14 Jul 2008 01:37:39 PM COT
Reason: Start method failed repeatedly, last exited with status 1.
  See: http://sun.com/msg/SMF-8000-KS
  See: man -M /usr/apache2/man -s 8 httpd
  See: /var/svc/log/network-http:apache2.log
Impact: This service is not running.
[root@BOCUNOCDWB04:~]#

Para configurar los servicios hay una consola a la que podemos acceder con svccfg.

[root@BOCUNOCDWB04:~]# svccfg
svc:> select network/http
svc:/network/http> select apache2
svc:/network/http:apache2> listprop
httpd                              application
httpd/stability                    astring  Evolving
httpd/ssl                          boolean  true
network                            dependency
network/entities                   fmri     svc:/milestone/network:default
network/grouping                   astring  require_all
network/restart_on                 astring  error
network/type                       astring  service
filesystem-local                   dependency
filesystem-local/entities          fmri     svc:/system/filesystem/local:default
filesystem-local/grouping          astring  require_all
filesystem-local/restart_on        astring  none
filesystem-local/type              astring  service
autofs                             dependency
autofs/entities                    fmri     svc:/system/filesystem/autofs:default
autofs/grouping                    astring  optional_all
autofs/restart_on                  astring  error
autofs/type                        astring  service
startd                             framework
startd/ignore_error                astring  core,signal
general                            framework
general/enabled                    boolean  true
start                              method
start/exec                         astring  "/lib/svc/method/http-apache2 start"
start/timeout_seconds              count    60
start/type                         astring  method
stop                               method
stop/exec                          astring  "/lib/svc/method/http-apache2 stop"
stop/timeout_seconds               count    60
stop/type                          astring  method
refresh                            method
refresh/exec                       astring  "/lib/svc/method/http-apache2 refresh"
refresh/timeout_seconds            count    60
refresh/type                       astring  method
restarter                          framework    NONPERSISTENT
restarter/transient_contract       count  restarter/logfile                  astring  /var/svc/log/network-http:apache2.log
restarter/contract                 count    299148
restarter/start_pid                count    23339
restarter/start_method_timestamp   time     1216060760.150109000
restarter/start_method_waitstatus  integer  0
restarter/auxiliary_state          astring  none
restarter/next_state               astring  none
restarter/state                    astring  online
restarter/state_timestamp          time     1216060760.155996000
restarter_actions                  framework    NONPERSISTENT
restarter_actions/restart          integer
restarter_actions/maint_off        integer
svc:/network/http:apache2>

La forma en que el daemon manejará los servicios se define en un script que tiene "métodos", que serán invocados por el daemon. Estos scripts están en /lib/svc/methods, y el daemon los llama por ejemplo de esta forma:

/lib/svc/methods/http-apache2 start

Adentro el método consulta algunas variables del servicio y lo levanta. El script es muy similar a los de /etc/init.d.

Con svcs se listan los servicios.
Con svcs -l se puede ver el estado actual de un determinado servicio. Además podes se puede ver el proceso principal y sus hijos:

 % svcs -p network/smtp:sendmail
    STATE          STIME    FMRI
    online         18:20:30 svc:/network/smtp:sendmail
     18:20:30      655 sendmail
     18:20:30      657 sendmail

Y con svcs -x se puede ver por qué un determinado servicio falló.

Tiene muchas más cosas locas. Yo creo que debe tener alguna forma de controlar servicios remotos, porque cada servicio tiene una URI que llaman FMRI (Fault Managed Resource Identifier), que puede ser algo así:

  • svc://localhost/system/system-log:default
  • svc:/system/system-log:default
  • system/system-log:default
Y en la primera opción justamente se define una location que en ese caso es localhost, pero supongo que uno podría poner una IP.

También hay otras cosas locas para el manejo de los runlevels del SO. Podés definir milestones que, si no entendí mal, serían como runlevels custom para los cuales vos podés definir qué servicios corren.

Más información sobre SMF en el System Administration Guide de Solaris: http://docs.sun.com/app/docs/doc/817-1985

Particularmente en estos dos capítulos:
http://docs.sun.com/app/docs/doc/817-1985/hbrunlevels-25516?a=view
http://docs.sun.com/app/docs/doc/817-1985/faauf?a=view

16/07/2008: Editado: Dejo un cheat-sheet de  SMF: http://www2.petervg.nl/quick_reference/SolarisSMF.pdf

WebAndBeer version 3

Ya tiene fecha y lugar el proximo WebAndBeer.

En esta version del evento, vamos a cambiar de lugar y forma del evento.

Invitamos a todos a participar del evento, que sera el dia miercoles 23 de julio a las 19:00hs en el CicloBar, Guatemala 5800 (esq. Carranza), Buenos Aires, Argentina.

Todos los que quieran llevar camaras y demas para registrar el evento haganlo, ya que como siempre nos colgamos y jamas queda nada registrado.

Por otro lado, estamos buscando sponsors, recuerden que el cambio es CV de los inscriptos a cambio de cervezas, asi que espero colaboren.

Hay que registrarse, pues es por cuestion de control y organizacion.



Promo_btn13

Arquitectura y escalabilidad de YouTube

Dando vueltas por esto de la internet y la blogosfera en la mañana de ayer, encontré un par de videos bastante interesantes a cargo de Cuong Do, uno de los ingenieros que estuvo en el desarrollo de youtube desde el comienzo y ahora es manager del grupo de ingeniería del core del producto.

La verdad hasta el momento solamente vi entero el primer video, en el cual Do habla sobre la arquitectura de youtube y cuenta algunos problemas que tuvieron. Entre ellos destaca uno con la forma de almacenar los thumbnails directamente en disco en una estructura "plana" de directorios y que les generó en determinado momento un conflicto en el file system que no entendí exactamente cuál fue, pero lo terminaron resolviendo con una estructura jerárquica de directorios. Luego también habla de otro problema con MySQL y unas placas que tenían que generaban unos problemas de voltage y les daban unos quilombos con un checksum (muy loco).

En cuanto a la arquitectura habla de que tienen una serie de servidores de balanceo que envian los requests a los web servers, e internamente como ya sabemos los recibe Apache para el contenido dinámico y el contenido estático se sirve con lighthttpd. Y luego tienen los servidores de memcache y los de bases de datos. También habla de unos servidores que creo que son de Google que los usan para tener como "más a mano" los videos más vistos.

En cuanto a tecnologías repite un poco lo que ya se sabe: Servidores Linux (SuSE), Apache y Lighthttpd, MySQL 5.0.X, el 99% del código en Python y usan toda la serie de recursos de Google a las que accedieron luego de la compra (el motor de búsqueda, el file system, y todas esas cosas locas para procesamiento distribuido que tiene Google).

Este es el video:



Fuente: Gigaom.


Luego, viendo los comentarios del post vi que uno indicaba que en esta otra conferencia Do habría hablado de lo mismo, así que la dejo también porque es más larga (52 minutos).






Link a Google Video

viernes, 4 de julio de 2008

El modelo de Drupal

El otro día estaba leyendo un post en un blog de un personaje conocido en el mundo de PHP, criticando a un framework, y me llamo la atención los puntos que marco como deficientes.

Que seria lo correcto o incorrecto ?

La realidad indica que lo funcional es lo correcto, pero es tan asi?

Nosotros sabemos que al mundo lo rigen ciertas reglas, de cosas que deberían ser, y realmente en PHP se hace lo que se quiere sin respetar estas reglas, y es muy difícil destacarse en este ambiente, tan mal visto por verdaderos gurus de la programacion. Al manejar muchos pseudo lenguajes (js, html, css, xml, json, etc), se complica un poco la organizacion, y si además a eso le agregamos que PHP es un hibrido que permite estructurado y POO. Y que hasta estos días no se conoce un estándar de código, mas allá de lo que tenemos en la documentacion de Zend, y que no somos muchos los que lo implementamos. Esto se traduce ha mucho código programado y pensado en muchas variedades diferentes.

Hace unos días empecé a trabajar con Drupal, para el frontend de un portal, y su código podría ser catalogado como incorrecto, pero la funcionalidad y la potencia de este CMS, lo hacen único. Su flexibilidad, su extensionalidad, y lo fácil que resulta lo hacen un gran CMS, sino el mejor. Pero la mayoría de su código son funciones, ni siquiera PHP4 solo funciones, bien estructurado, muchas de esas funciones nos devuelven HTML puro, así es HTML en una función, y generamos las distintas partes de un themes a través de esto.

Y para seguir hablando de lo poco correcto del código, tengo que decirles otra cosa mas (lo que va a leer ahora puede ser nocivo para la salud), usa variables globales!.

Sin embargo Drupal es el CMS mas popular, eficiente, fácil, y extensible del mercado.

Así y todo yo apoyo 100% el uso POO en PHP, creo que PHP5 es uno de los grandes avances que tuvimos, y es la forma en que la gente de Zend nos dice, "Estamos evolucionando, sigan con nosotros", no solo PHP5, sino los magníficos Frameworks que tenemos hoy en el mercado como symfony y Zend Framework, entre otros, que día a día siguen extendiendo funcionalidades, de la mejor forma posible usando POO.

Posibles soluciones: que en las próximas versiones la gente de Zend, elimine la programacion estructurada de su código, y obliga al mejor ejemplo java a usar solo POO, pero esto tiene mas de una contra, va a perder popularidad, el costo de aprendizaje va a ser mayor. Pero vamos a ser mas respetados como programador, los que sigamos con PHP, vamos a tener un camino definido bajo estándares de código, y siguiendo una linea. Sin embargo no creo que sea lo mejor.

En definitiva, creo que lo mejor es que tomemos el tren que mejor nos quede.

Ustedes que piensan?

Enlaces:
Drupal
Zend Framework
Symfony
Estandar de código

martes, 1 de julio de 2008

Web Services - Introduccion

¿Que son?
Un web service es un conjunto de estándar y protocolo que sirve para intercambiar información entre distintos sistemas. Un sistema desarrollado con cierta tecnología, por ejemplo Java, puede comunicarse con un sistema en PHP a través de un Web Services, esta es la funcionalidad principal, pero no necesariamente tienen que ser de diferentes plataformas, los sistemas pueden estar realizados en un mismo lenguaje, por Ejemplo comunicar dos sistemas realizados en PHP a través de un web service.

Esto se consigue gracias al uso de estándar abiertos que son regulados por la W3C y OASIS encargados de dicha tarea.


Los estándar que se manejan en un web Service, son Web Services Protocol Stack, XML, SOAP, XML-RCP, HTTP, FTP, SMTP, WSDL, UDDI, y WS-Security

Un ejemplo de utilizacion de un web Service.

La cadena de Hoteles OneTravel, se asocia con la agencia de viajes EcoSpace.

Cada empresa tiene un sistema particular para cada empresa, pero surge la necesidad de reservar una habitación desde el sistema de EcoSpace que repercuta en OneTravel, para saber si tiene disponibilidad para cierta fecha, durante ciertos días. Esta comunicacion la podemos hacer a través de un Web Service.

OneTravel, tiene un WebService (desde ahora WS), en el cual nosotros podemos conseguir.

- El listado de los hoteles asociados a OneTravel.
- Interfaz para reservar una habitación
- Interfaz para liberar una reserva
- Interfaz para saber los detalles de los servicios.


EcoSpace al poder interactuar con OneTravel de forma remota y en linea, se puede reservar una habitación desde el sistema de EcoSpace de forma automatizada y que impacte en el sistema de OneTravel, sin la necesidad de correos electrónicos, o llamadas por teléfono para confirmar, de esta forma nosotros impactamos directamente sobre el sistema de OneTravel.

Los Web Service no solo nos sirven para hacer reservas en un hotel desde una agencia de viajes, sino para cualquier tipo de comunicacion a través de sistemas diferentes. A nuestros WS le podemos dar la cantidad de funcionalidades que necesitemos.



Ventajas de un web Services
Los WS tienen muchas ventajas.
Son puentes de comunicacion a través de aplicaciones desarrolladas en diferentes plataformas independientemente de sus propiedades o plataforma en la que se instale. Una aplicacion desarrollada en Linux, se puede comunicar tranquilamente con una aplicacion desarrollada para Windows.

Se puede dar que una aplicacion solo englobe a un conjunto de WS. Por ejemplo un home Banking. Nosotros autenticamos nuestros datos a un servidor especial que Corre una aplicacion en C que corre sobre un Debian, también tenemos la conexión, con las diferentes empresas de tarjeta de créditos (American Express, Visa, Master, Cabal, etc), esta comunicacion se hace a través de un WS que es administrado por cada empresa. Ademas tenemos el WS de pagomiscuentas.com, que a su vez se conecta con los WS de otras empresas y a su vez con mas WS, permitiendo al usuario pagar la cuenta de teléfono de su casa, a través de su Home Banking, sin la necesidad de ir a los cajeros de esta empresas.


Desventajas
El problema principal que tiene un WS es el rendimiento, al ser un estándar basado en texto, resulta ser mas pesado que con otros estándar de comunicacion.
Al ser procesado por el puerto de HTTP, algunas reglas de los firewall pueden ser violadas.


¿Por que crear un WS?
Los WS son fácil de implementar, tanto para la creación de un WS, como para la implementación y uso de este. A medida que pasa el tiempo mas aplicaciones usan los WS para comunicarse, y esto hace que se genere mas información, y sea mas común hablar de WS. Es comun encontrar en grandes organizaciones uno o mas sistemas internos desarrollados en algún lenguaje para crear aplicaciones de escritorio, y con el crecimiento y auge de Internet, el uso de aplicaciones vía web crece dia a dia. Lenguajes como PHP pueden comunicarse muy facilmente con estos sistemas para brindar informacion o interactuar con un usuario via web.


Referencias
OASIS http://www.oasis-open.org
W3C http://www.w3c.es/Consorcio/