domingo, 2 de marzo de 2014

Raspberry Pi: Montar clientes Torrent, aMule y servidor ownCloud

Montamos cliente Torrent con Raspberry Pi. Instalación:

pi@raspberrypi ~ $ sudo apt-get -y install transmission-daemon
Lo paramos y configuramos, usaremos disco duro externo:

pi@raspberrypi ~ $ sudo /etc/init.d/transmission-daemon stop
pi@raspberrypi ~ $ cd /media/descargas
pi@raspberrypi ~ $ mkdir torrent
pi@raspberrypi ~ $ cd torrent
pi@raspberrypi ~ $ mkdir finish
pi@raspberrypi ~ $ mkdir temp
pi@raspberrypi ~ $ chmod 777 finish
pi@raspberrypi ~ $ chmod 777 temp
ls -l
Configuración:

pi@raspberrypi ~ $ sudo vi /var/lib/transmission-daemon/info/settings.json
Campos que tenemos que modificar:

“download-dir”: “/media/descargas/torrent/finish”
“incomplete-dir-enabled”: true
“incomplete-dir”: “/media/descargas/torrent/temp”
“rpc-enabled”: true
“rpc-bind-address”: “0.0.0.0″
“rpc-username”: “transmission”
"rpc-whitelist": "127.0.0.1"
“rpc-whitelist-enabled”: false
Arrancamos el servicio:

pi@raspberrypi ~ $ sudo /etc/init.d/transmission-daemon start
Y accedemos desde nuestro ordenador al cliente torrent de la Raspberry Pi. Le pusimos ip estatica y el usuario y la clave por defecto es "transmission":

http://192.168.1.32:9091/transmission Configuración aMule Instalamos el demonio:

pi@raspberrypi ~ $ sudo aptitude install amule-daemon
Indicamos un usuario:

pi@raspberrypi ~ $ sudo vi /etc/default/amule-daemon

# Configuration for /etc/init.d/amule-daemon

# The init.d script will only run if this variable non-empty.
AMULED_USER="pi"

# You can set this variable to make the daemon use an alternative HOME.
# The daemon will use $AMULED_HOME/.aMule as the directory, so if you
# want to have $AMULED_HOME the real root (with an Incoming and Temp
# directories), you can do `ln -s . $AMULED_HOME/.aMule`.
AMULED_HOME=""
Comando para iniciar, parar... el demonio

pi@raspberrypi ~ $ sudo /etc/init.d/amule-daemon start
pi@raspberrypi ~ $ sudo /etc/init.d/amule-daemon stop
Generamos contraseña, harán falta dos, una para la aplicación, y otra para para la gestión a través de la aplicación web

pi@raspberrypi ~ $ echo -n "contraseña" | md5sum
4c882dcb24bcb1bc225391a602feca7c  -
Configuramos la aplicación:

vi ~/.aMule/amule.conf

AcceptExternalConnections=1
ECPassword=4c882dcb24bcb1bc225391a602feca7c valor md5 de la contraseña
[WebServer]
Enabled=1
Password=4c882dcb24bcb1bc225391a602feca7c 
AllocateFullFile=1 # Reserva el espacio
Generamos la configuración de la aplicación web aMule usando la configuración de la aplicación

amuleweb --create-config-from=/home/username/.aMule/amule.conf
Se puede editar. Para que funcionara tuve que poner claves con mayúsculas tanto en amule.conf como en remote.conf

pi@raspberrypi ~ $ vi .aMule/remote.conf

Locale=
[EC]
Host=localhost
Port=4712
Password=4c882dcb24bcb1bc225391a602feca7c
[Webserver]
Port=4711
UPnPWebServerEnabled=0
UPnPTCPPort=50001
Template=
UseGzip=1
AllowGuest=0
AdminPassword=4c882dcb24bcb1bc225391a602feca7c
GuestPassword=
Reiniciamos el demonio y vamos a la ip estatica de la Raspberry Pi en el puerto por defecto:
pi@raspberrypi ~ $ sudo /etc/init.d/amule-daemon restart
[ ok ] Restarting aMule daemon: amuled.
http://192.168.1.32:4711/amuleweb-main-dload.php Server Recomendados:

!! Saugstube !!
ed2k://|server|193.138.221.214|4242|/

#eMule Serverlist Nr.1#
ed2k://|server|193.138.221.213|4242|/

#eMule Serverlist Nr.2#
ed2k://|server|193.138.221.210|4242|/

..:: France Mule #1 ::..
ed2k://|server|193.42.213.30|9510|/

eDonkeyServer No1
ed2k://|server|77.247.178.244|4242|/
Instalación de servidor OwnCloud Instalamos servidor Apache:
pi@raspberrypi ~ $ sudo apt-get install apache2 php5 php5-json php5-gd php5-sqlite curl libcurl3 libcurl3-dev php5-curl php5-common php-xml-parser
Instalamos base de datos SQLite:
pi@raspberrypi ~ $ sudo apt-get install sqlite
Nos descargamos el OwnCloud:
pi@raspberrypi ~ $ cd tmp
pi@raspberrypi ~/tmp $ wget download.owncloud.org/community/owncloud-5.0.0.tar.bz2
Descomprimir el archivo y copiarlo en el directorio /var/www
pi@raspberrypi ~/tmp $ sudo tar -xjf owncloud-5.0.0.tar.bz2 -C /var/www
Cambiar propietarios de la carpeta OwnCloud.
pi@raspberrypi ~ $ sudo chown www-data:www-data -R /var/www/owncloud
pi@raspberrypi ~ $ sudo chown www-data:www-data -R /media/descargas #Disco Duro Externo puede fallar
Editar el tamaño máximo de subida de archivos en Apache. Indicamos 2G.
sudo vi /etc/php5/apache2/php.ini

# /etc/php5/apache2/php.ini
upload_max_size = 2048 M
post_max_size = 2048 M
Reiniciamos Apache:
pi@raspberrypi ~ $ sudo service apache2 restart
Para que owncloud vaya mas rápido, instalar el acelerador php cache y reiniciar el apache:
pi@raspberrypi ~ $ sudo apt-get install php-apc
pi@raspberrypi ~ $ sudo service apache2 restart
Comprobamos que esta funcionando y acabamos la instalación http://tuip/owncloud Nos muestra un error:
Los datos del directorio (carpeta /media /descargas/) es legible para otros usuarios
Por favor, cambie los permisos a 0770 Sun que el directorio no se pueden enumerar por otros usuarios.
Se soluciona editando el fichero /var/www/owncloud/lib/util.php y comentamos parte del código, quedando así:
/*if (stristr(PHP_OS, 'WIN')) {
        //TODO: permissions checks for windows hosts
} else {
        $permissionsModHint = 'Please change the permissions to 0770 so that the directory'
                .' cannot be listed by other users.';
        $prems = substr(decoct(@fileperms($dataDirectory)), -3);
        if (substr($prems, -1) != '0') {
                OC_Helper::chmodr($dataDirectory, 0770);
                clearstatcache();
                $prems = substr(decoct(@fileperms($dataDirectory)), -3);
                if (substr($prems, 2, 1) != '0') {
                        $errors[] = array('error' => 'Data directory ('.$dataDirectory.') is readable for other users',
                                'hint' => $permissionsModHint);
                }
        }
}*/
Solo falta crear usuario en ownCloud y que las descargas vayan a su carpeta files o crear enlaces blandos. PD. Hacer que transmission, amule y owncloud se lleven bien. fuente molesybits. Para evitar el parche de los permisos de owncloud hay que hacer que los usuarios www-data y debian-transmission se lleven bien haciendo que ambos usuarios compartan el mismo grupo editando /etc/group:
pi@raspberrypi ~ $ sudo vi /etc/group
Buscamos el grupo debian-transmission y añadimos a los usuarios pi y www-data, quedando la linea:
#/etc/group

debian-transmission:x:111:pi:www-data
Y damos permisos al usuario www-data a la carpeta owncloud del disco duro externo si fuera necesario.
pi@raspberrypi ~ $ cd /media/descargas/owncloud
pi@raspberrypi ~ $ sudo chown -R www-data:debian-transmission data
y reiniciamos los servicios:
pi@raspberrypi ~ $ sudo service apache2 restart
pi@raspberrypi ~ $ sudo service transmission-daemon restart

domingo, 16 de febrero de 2014

Raspberry Pi: Configurar ip fija, acceso ssh y montarle disco duro externo

Conectamos la Raspberry Pi a al router y vemos que ip tiene o le conectamos un teclado y una pantalla abrimos una consola y tecleamos ifconfig.

pi@raspberrypi ~ $ ifconfig
eth0      Link encap:Ethernet  HWaddr b8:27:eb:e7:76:6d  
          inet addr:192.168.1.31  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:463 errors:0 dropped:3 overruns:0 frame:0
          TX packets:334 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:48748 (47.6 KiB)  TX bytes:36262 (35.4 KiB)

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:0 errors:0 dropped:0 overruns:0 frame:0
          TX packets:0 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:0 (0.0 B)  TX bytes:0 (0.0 B)

wlan0     Link encap:Ethernet  HWaddr 80:1f:02:af:2c:ef  
          inet addr:192.168.1.32  Bcast:192.168.1.255  Mask:255.255.255.0
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:507 errors:0 dropped:526 overruns:0 frame:0
          TX packets:5 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:103617 (101.1 KiB)  TX bytes:1195 (1.1 KiB)
Nos conectamos a traves de ssh. ssh -X pi@192.168.1.13 y he introducimos la clave. Por defecto "raspberry"

verdor@enlamina ~$ ssh pi@192.168.1.31
Linux raspberrypi 3.6.11+ #474 PREEMPT Thu Jun 13 17:14:42 BST 2013 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Feb 16 21:58:15 2014 from 192.168.1.33
pi@raspberrypi ~ $ 
Asignamos una ip fija a la Raspberry Pi. Se configura en /etc/network/interfaces

pi@raspberrypi ~ $ sudo vi /etc/network/interfaces

#/etc/network/interfaces
auto lo

iface lo inet loopback
#iface eth0 inet dhcp
iface eth0 inet static

address 192.168.1.31
gateway 192.168.1.1
netmask 255.255.255.0

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
#iface default inet dhcp
iface default inet static
address 192.168.1.32
netmask 255.255.255.0
gateway 192.168.1.1
Reiniciamos la Raspberry Pi para ver que tome los cambios:

pi@raspberrypi ~ $ sudo reboot
Queremos autenticarnos a la Raspberry Pi a través de una llave ssh, ya tenemos una. Hacemos en el servidor, la Raspberry Pi:

pi@raspberrypi ~ $  pwd
/home/pi
pi@raspberrypi ~ $ mkdir .ssh; chmod 700 .ssh
pi@raspberrypi ~ $ cd .ssh
pi@raspberrypi ~ $ touch authorized_keys; chmod 600 authorized_keys
En el cliente:

verdor@enlamina ~$ cd ~/.ssh
verdor@enlamina ~$ cat id_dsa.pub| ssh pi@192.168.1.32 'cat - >> ~/.ssh/authorized_keys'
Ahora configuramos ssh para acceder mas fácilmente a la Raspberry Pi:

verdor@enlamina ~$ vi ~/.ssh/config

#/home/verdor/.ssh/config

Host raspberrypi
  User pi
  HostName 192.168.1.31
  IdentityFile /home/verdor/.ssh/id_rsa
Guardamos con wq y entramos en la Raspberry Pi

verdor@enlamina ~$ ssh raspberrypi 
Linux raspberrypi 3.6.11+ #474 PREEMPT Thu Jun 13 17:14:42 BST 2013 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sun Feb 16 22:49:09 2014 from 192.168.1.33
pi@raspberrypi ~ $ 
Montamos disco duro externo para datos. Buscamos dispositivos conectados:

pi@raspberrypi ~ $  lsusb
Bus 001 Device 002: ID 0424:9514 Standard Microsystems Corp. 
Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp. 
Bus 001 Device 004: ID 7392:7811 Edimax Technology Co., Ltd EW-7811Un 802.11n Wireless Adapter [Realtek RTL8188CUS]
Bus 001 Device 005: ID 152d:2329 JMicron Technology Corp. / JMicron USA Technology Corp. JM20329 SATA Bridge
Averiguamos como se llama el dispositivo:

pi@raspberrypi ~ $ blkid
/dev/mmcblk0p1: LABEL="RECOVERY" UUID="242D-1618" TYPE="vfat" 
/dev/mmcblk0p5: SEC_TYPE="msdos" LABEL="boot" UUID="676B-0317" TYPE="vfat" 
/dev/mmcblk0p6: UUID="0eb36e9e-40f5-47f4-a751-4e197c0dd7c8" TYPE="ext4" 
/dev/sda1: UUID="XXXX-XXXX" TYPE="vfat"
Para obtener información mas detallada de la lista de las unidades conectadas:

pi@raspberrypi ~ $ sudo fdisk -l

Disk /dev/mmcblk0: 7861 MB, 7861174272 bytes
4 heads, 16 sectors/track, 239904 cylinders, total 15353856 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000ba6a2

        Device Boot      Start         End      Blocks   Id  System
/dev/mmcblk0p1            2048     2466796     1232374+   e  W95 FAT16 (LBA)
/dev/mmcblk0p2         2473984    15353855     6439936   85  Linux extended
/dev/mmcblk0p5         2482176     2596863       57344    c  W95 FAT32 (LBA)
/dev/mmcblk0p6         2605056    15353855     6374400   83  Linux

Disk /dev/sda: 120.0 GB, 120034123776 bytes
255 heads, 63 sectors/track, 14593 cylinders, total 234441648 sectors
Units = sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disk identifier: 0x000683e5

   Device Boot      Start         End      Blocks   Id  System
/dev/sda1              63   234436544   117218241    c  W95 FAT32 (LBA)
Creamos carpeta para el disco duro:

pi@raspberrypi ~ $ sudo mkdir /media/descargas
Editamos /etc/fstab para que se monte automáticamente al arrancar, añadimos la ultima linea:

pi@raspberrypi ~ $ sudo vi /etc/fstab

# /etc/fstab
proc            /proc           proc    defaults          0       0
/dev/mmcblk0p5  /boot           vfat    defaults          0       2
/dev/mmcblk0p6  /               ext4    defaults,noatime  0       1
# a swapfile is not a swap partition, so no using swapon|off from here on, use  dphys-swapfile swap[on|off]  for that
UUID="XXXX-XXXX" /media/descargas vfat  defaults
Damos permisos de lectura y escritura al directorio de montaje:

pi@raspberrypi ~ $ sudo chmod -Rf 777 /media/descargas
Y montamos o reiniciamos:

pi@raspberrypi ~ $ sudo mount -a
Lo próximo será montar clientes Torrent, aMule y servidor Owncloud

miércoles, 27 de noviembre de 2013

Validación XML

1ª Opción
dtd = XML::Dtd.new(IO.read(dtd_path, encoding: "UTF-8"))
document = io ? XML::Document.io(xml[:tempfile], encoding: XML::Encoding::ISO_8859_1) : document = XML::Document.file(xml, encoding: XML::Encoding::ISO_8859_1)
document.validate(dtd)


2ª Opción
xsd = Nokogiri::XML::Schema(File.read(PO_SCHEMA_FILE))
doc = Nokogiri::XML(File.read(PO_XML_FILE))
xsd.validate(doc).each do |error|
  puts error.message
end

http://www.xmlsoft.org/xmldtd.html
http://www.xmlvalidation.com/

sábado, 21 de enero de 2012

Recordatorio RVM, instalación y uso

  • ¿que es RVM?
    Ruby Version Manager permite gestionar varios entornos de desarrollo Ruby por versiones y dentro de cada versión de Ruby, distintos entornos mediante diferentes conjuntos de conjuntos de gemas. Para cada Ruby hay un gemset Global al que acceden todos los demás gemset

  • Instalación de RVM:
    bash -s stable < <(curl -s https://raw.github.com/wayneeseguin/rvm/master/binscripts/rvm-installer)
    

    Añadimos la siguiente línea al fichero de configuración ~/.bashrc, teniendo en cuenta que no haya ningún “return” antes:
    echo '[[ -s "$HOME/.rvm/scripts/rvm" ]] && . "$HOME/.rvm/scripts/rvm" # Load RVM function' >> ~/.bash_profile
    
    Abrimos otro shell y comprobamos que se haya instalado correctamente
    type rvm | head -1 #la salida sera rvm is a function
    
  • Instalar una versión de ruby con RVM
    
    rvm install ruby-1.9.3-p0 # ultima versión estable
    rvm --default use ruby-1.9.3-p0 #lo dejamos por defecto
    ruby -v # compruebo con que versión estoy trabajando
    
  • Pregunto por la versión de rubygem:
    gem -v #si es menor de 1.8.11 la actualizamos
    gem update –system #actualizacion (no os hará falta)
    
  • Crear un gemset (entorno de trabajo para rails 3.2.0) , actualizo gema rake si es necesario
    rvm ruby-1.9.3-p0@rails320 --create --default # creo entorno rails320 por defecto
    
    rvm gemset list #comprobamos que se ha creado
    
    gem list #pedimos que nos muestre la información actual sobre las gemas que tenemos
    
    gem update rake # si la versión de rake es menor que 0.9.2.2 actualizamos
    
    rake -version rvm install ruby-1.9.3-p0 # ultima versión estable
    
  • Instalamos rails 3.2.0 (http://rubygems.org/gems/rails):

    gem install rails -v 3.2.0.rc2 # le indicamos la ultima versión apunto de salir, en breve estable

    # gem install rails #toma la última versión estable
    rails -v # Consulta la versión de la gema rails

  • listado de otros comandos:
    • rvm info # información de configuración y sistema
    • rvm list # lista de rubies instalados
    • rvm list known # lista de rubies que se pueden instalar
    • rvm gemset list # lista de gemset
    • rvm gemset list_all # lista de gemsets en cada ruby
    • rvm gemset create rails312 # crea el gemset rails312
    • rvm ruby-1.9.3-p0@rails312 # nos movemos al nuevo gemset
    • rvm gemset use rails312 # moverse de gemset dentro de la misma versión de ruby
    • gem install rails -v 3.1.2 # instalamos en este gemset la versión de rails 3.1.2
    • #rvm gemset delete rails312 #borramos el gemset rails312
    • #rvm uninstall ree,1.8.7 #borramos ruby con passenger y ruby 1.8.7
  • Puedes crear ficheros de configuración el tus proyectos en un fichero .rvmrc y así cuando cambias de directorio cargas el entorno correcto, versión de ruby y conjunto de gemas: http://beginrescueend.com/workflow/rvmrc/
    
        # ../myapp/.rvmrc
        rvm_gemset_create_on_use_flag=1
        rvm use 1.9.3-p0
        rvm gemset use rails320myapp

  • También puedes configurar el prompt para que te indique la configuración con la que estas trabajando: http://beginrescueend.com/workflow/prompt/

Fuente: RVM
código

jueves, 12 de mayo de 2011

Generar pdf con wicked_pdf en Rails

Wicked PDF usa un ejecutable llamado wkhtmltopdf para generar un fichero PDF desde un fichero HTML. Nos bajamos el conversor que le corresponda a nuestra maquina y lo ponemos en /usr/local/bin/. Como he descomprimido el ficher en mi HOME, el comando es:

sudo mv wkhtmltopdf-tu_version /usr/local/bin/

Instalamos la gema como plugin en nuestra aplicacion Rails:

script/plugin install git://github.com/mileszs/wicked_pdf.git
script/generate wicked_pdf

Tenemos que configurar el plugin para que sepa que versión del Wicked hemos instalado y donde esta. Para ello en config/enviroments.rb (rails 1.x), o donde corresponda en tu aplicación, ponemos algo así:


WickedPdf.config = {
:exe_path => '/usr/local/bin/wkhtmltopdf-amd64',
:zoom => 1.0,
:margin => { :top => 10,:bottom => 10, :left => 10, :right => 10},
:outline => { :outline => true },
:disable_smart_shrinking => false
}


Hay muchas mas posibles opciones, que también se pueden cambiar cuando llamamos a la vista desde el controlador:

def show
respond_to do |format|
format.html
format.pdf do
render :pdf => "file_name"
end
end
end


Fuentes: github, bunario wkhtmltopdf, uso y configuracion por snikt

miércoles, 27 de abril de 2011

jueves, 14 de abril de 2011

Gmate, Gedit como TextMate con Ubuntu

Paso 1: Agregar el repositorio de Ubuntu on Rails

sudo apt-add-repository ppa:ubuntu-on-rails/ppa
sudo apt-get update

Paso 2: Instalar el paquete

sudo aptitude install gedit-gmate

Paso 3: Instalar otros plugins

sudo apt-get install gedit-plugins

nueva ruta gedit3: ~/.local/share/gedit/plugins

Paso 4: Uso y configuración de algunos plugins sacado de josemariaberlanga

  1. Align: alinea bloques de texto en columnas

  2. Class Browser: en ruby y RoR usamos clases, nos será muy útil este navegador de clases para manejar funciones y variables.

  3. Document Statistics: no es primordial pero me gusta saber el número de lineas que llevo escritas, número de palabras, espacios en blanco, etc.

  4. External Tools: añade una nueva opción al menú Tools, desde ahi podremos ejecutar comandos como en un shell, muy útil para ejecutar todas las posibilidades de un proyecto Ruby on Rails.

  5. File Browser Pane: fundamental. Un navegador de archivos para movernos rapidamente por las carpetas del proyecto.

  6. Find in Files: encuentra en todos los archivos de tu root de proyecto (busca en todos los archivos dentro de la carpeta donde te encuentres en el navegador de archivos).

  7. Gemini: útil si te acostumbras, cierra parentesis, corchetes y comillas dobles.

  8. Go to File: una forma fácil para moverte entre archivos. Potente si lo manejas desde el teclado.

  9. Rails Extract Partial: un plugin que nos facilita sacar parciales con sólo pulsar un botón. Muy útil en ciertos momentos.

  10. Rails File Loader: identifica si un archivo es parte de un proyecto Ruby on Rails y lo señala como lenguaje.

  11. Rails Hot Command: una opción que se nos abre con todas las opciones de comandos que dispone Rails, muy útil si estamos empezando y aún no los sabemos. Aún después nos será de ayuda a veces jeje

  12. TabSwitch: se nos activa la posibilidad de cambiar de pestaña con Ctrl-tab.

  13. Word Completion: completa la palabra que estemos escribiendo. Es útil pero hay que tener cuidado de no caer demasiado, pues a veces las sugerencias pueden dar caso a error. Es un plugins que necesita aún mejorar.

  14. TextMate Style Autocompletion: completa la palabra que estemos escribiendo pulsando Esc, con cada pulsación muestra una nueva palabra, necesita configuración y no es compatible con Word Completion

  15. Zen Coding: Este plugins es útil sobretodo si no usamos gemas como haml -el cual recomiendo-. No ayudará a escribir código html, hay varios tutoriales por internet pero basicamente escibes la palabra clave y pulsando Ctrl+E se escribe el codigo HTML.

  16. Comentar codigo: comentamos el texto seleccionado con Ctrl-M, descomentamos con Ctrl-Mays-M

  17. Mostrar espacios: dibuja los espacio con un punto, interesante para ver sangria


Fuentes: gmate, josemariaberlanga, joserojas