You are here:
Wiki-SL
>
TWikiBar Web
>
TWikiBarConversa008
(06 Feb 2008,
CollonsTorre
)
(raw view)
E
dit
A
ttach
---+!! Conversación de bar Parte VIII --- %TOC% --- - Hola amigo, como estás? - Muy bien!, quería mostrarte lo que hice, pero ya sé que tu quieres ir rápido a lo que interesa, no? - Solo para llevarte la contraria, hoy voy a dejar que me muestres tu "programita". Venga, muéstrame lo que hiciste. - Ahhh ... el ejercicio que me pasaste es muy extenso. Yo lo resolví así: %TERMINAL_INI% $ cat musinc5%OUT_INI% #!/bin/bash # Registra CDs (versión 5) # clear <nop>LineaMesg=$((`tput lines` - 3)) # Linea que define cuantos mensajes serán pasados de una vez a la pantalla <nop>TotCols=$(tput cols) # Cantidad de columnas de la pantalla para encuadrar mensajes echo " Inclusión de Músicas !========= !== !======= Título del Álbum: | Este campo fue Pista: < creado solamente para | orientar como llenar Nombre de la Música: Intérprete:" # Pantalla montada con un único echo while true do tput cup 5 38; tput el # Posiciona y limpia linea read Albun [ ! "$Albun" ] && # Operador pulso <ENTER> { Msg="Desea Terminar? (S/n)" !TamMsg=${#Msg} Col=$(((!TotCols - !TamMsg) / 2)) # Centra mensaje en la linea tput cup $LineaMesg $Col echo "$Msg" tput cup $LineaMesg $((Col + !TamMsg + 1)) read -n1 SN tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla [ $SN = "N" -o $SN = "n" ] && continue # $SN es igual a N o (-o) n? clear; exit # Fin de la ejecución } grep "^$Albun\^" musicas > /dev/null && { Msg="Este álbum ya está incluido" !TamMsg=${#Msg} Col=$(((!TotCols - !TamMsg) / 2)) # Centra mensaje en la linea tput cup $LineaMesg $Col echo "$Msg" read -n1 tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla continue # Vuelve para leer otro álbum } Reg="$Albun^" # $Reg recibirá los datos para grabación elArtista= # Variable que graba artista anterior while true do ((Track++)) tput cup 7 38 echo $Track tput cup 9 38 # Posiciona para leer música read Musica [ "$Musica" ] || # Si el operador escribio <ENTER>... { Msg="Fin del Álbum? (S/n)" !TamMsg=${#Msg} Col=$(((!TotCols - !TamMsg) / 2)) # Centra mensaje en la linea tput cup $LineaMesg $Col echo "$Msg" tput cup $LineaMesg $((Col + !TamMsg + 1) read -n1 SN tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla [ "$SN" = N -o "$SN" = n ]&&continue # $SN es igual a N o (-o) n? break # Sale del loop para grabar } tput cup 11 38 # Posiciona para leer Artista [ "$elArtista" ]&& echo -n "($elArtista) " # Artista anterior es default read Artista [ "$Artista" ] && elArtista="$Artista" Reg="$Reg$elArtista~$Musica:" # Montando registro tput cup 9 38; tput el # Borra Música de la pantalla tput cup 11 38; tput el # Borra Artista de la pantalla done echo "$Reg" >> musicas # Graba registro en el fin del archivo sort musicas -0 musicas # Clasifica el archivo done%OUT_FIM% %TERMINAL_FIM% - Si, el programa esta bien, esta todo bien estructurado, pero me gustaría comentarte un poco lo que hiciste: * Solo para recordarte, las siguientes construcciones: =[ ! $Albun ] &&= y =[ $Musica ] ||= representan lo mismo, en el primer caso, comprobamos si la variable =$Album= no (=!=) tiene nada dentro, entonces (=&&=) ... y en el segundo, comprobamos lo mismo en =$Musica=, si no (=||=) ... * Si te quejaste por el tamaño, es porque todavía no te pase algunos trucos. Fíjate que la mayor parte del _script_ es para dar mensajes centrados en la penúltima linea de la pantalla. Fíjate también que algunos mensajes piden un S o un N y otros son sólo de advertencia. Sería el caso típico del uso de funciones, que serían escritas solamente una vez y llamadas para ejecutar en diversos puntos del _script_ . Voy a hacer dos funciones para resolver estos casos y vamos a incorporarlas a tu programa para ver el resultado final. ---++ Funciones - Mozo! Ahora tráeme dos "chops" bien helados, uno sin espuma, para que me de inspiración. <verbatim> Pregunta () { # La función recibe 3 parámetros en el siguiente orden: # $1 - Mensaje que será mostrado en la pantalla # $2 - Valor que será aceptado como respuesta por defecto # $3 - Otro valor aceptado # Suponiendo que $1=Acepta?, $2=s y $3=n, la linea a # seguir colocaría en Msg el valor "Acepta? (S/n)" local Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" local TamMsg=${#Msg} local Col=$(((TotCols - TamMsg) / 2)) # Centra mensaje en la linea tput cup $LineaMesg $Col echo "$Msg" tput cup $LineaMesg $((Col + TamMsg + 1)) read -n1 SN [ ! $SN ] && SN=$2 # Si esta vacía coloca por defecto en SN echo $SN | tr A-Z a-z # La salida de SN será en minúscula tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla return # Sale de la función } </verbatim> Como podemos ver, una función es definida cuando hacemos =nombre_de_la_función ()= y todo su cuerpo esta entre llaves (={}=). Así como charlamos aquí en el Bar sobre pasar parámetros, las funciones los reciben de la misma forma, o sea, son parámetros de posición (=$1, $2, ..., $n=) y todas las reglas que se aplican al pase de parámetros para programas, también valen para funciones, pero es muy importante aclarar que los parámetros pasados hacia un programa no se mezclan con aquellos que éste pasó hacia sus funciones. Esto significa, por ejemplo, que el =$1= de un _script_ es diferente del =$1= de una de sus funciones. Fíjate que las variables =$Msg=, =$TamMsg= y =$Col= son de uso restringido de esta rutina, y por eso fueron creadas como =local=. La finalidad de esto es simplemente economizar memoria, ya que al salir de la rutina, todas serán destruidas y si no hubiese usado esta opción, se quedarían residentes en la memoria. La linea de código que crea =local Msg=, junta el texto recibido (=$1=) abre paréntesis, la respuesta _default_ (=$2=) en mayúscula, una barra, la otra respuesta (=$3=) en minúscula y finaliza cerrando el paréntesis. Uso esta forma para, que al mismo tiempo, pueda mostrar las opciones disponibles y destacar la respuesta ofrecida como _default_. Casi al final de la rutina, la respuesta recibida (=$SN=) se pasa a minúscula de forma que en el cuerpo del programa no se necesite hacer esta prueba. Veamos ahora como quedaría la función para presentar un mensaje en la pantalla: <verbatim> function MandaMsg { # La función recibe solamente un parámetro # con el mensaje que se desea mostrar, # para no obligar al programador que pase # el mensaje entre comillas, usaremos $* (todos # los parámetros, te acuerdas?) y no $1. local Msg="$*" local TamMsg=${#Msg} local Col=$(((TotCols - TamMsg) / 2)) # Centra el mensaje en la linea tput cup $LineaMesg $Col echo "$Msg" read -n1 tput cup $LineaMesg $Col; tput el # Borra el mensaje de la pantalla return # Sale de la función } </verbatim> Esta es otra forma de definir una función: no la llamamos como en el ejemplo anterior usando una construcción con la sintaxis =nombre_de_la_función ()=, sino como =function nombre_de_la_función=. No tiene ninguna diferencia con la anterior, excepto que, como consta en los comentarios, usamos la variable =$*= que como ya sabemos es el conjunto de todos los parámetros pasados, para que el programador no necesite usar comillas envolviendo el mensaje que desea pasar para la función. Para terminar con este blá-blá-blá vamos a ver entonces las alteraciones que el programa necesita cuando usamos el concepto de funciones: %TERMINAL_INI% $ cat musinc6%OUT_INI% #!/bin/bash # Registra CDs (versión 6) # # Área de las variables globales !LineaMesg=$((`tput lines` - 3)) # Linea que mensajes serán dados para el operador !TotCols=$(tput cols) # Cantidad de columnas de la pantalla para encuadrar mensajes # Área de las funciones Pregunta () { # La función recibe 3 parámetros en el siguiente orden: # $1 - Mensaje que será mostrado en la pantalla # $2 - Valor que será aceptado como respuesta default # $3 - Otro valor aceptado # Suponiendo que $1=Acepta?, $2=s y $3=n, la linea a # seguir colocaría en Msg el valor "Acepta? (S/n)" local Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" local !TamMsg=${#Msg} local Col=$(((!TotCols - !TamMsg) / 2)) # Centra mensaje en la linea tput cup $LineaMesg $Col echo "$Msg" tput cup $LineaMesg $((Col + !TamMsg + 1)) read -n1 SN [ ! $SN ] && SN=$2 # Si vacia coloca default en SN echo $SN | tr A-Z a-z # La salida de SN será en minúscula tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla return # Sale de la función } function !MandaMsg { # La función recibe solamente un parametro # con el mensaje que se desea mostrar, # para no obligar al programador que pase # el mensaje entre comillas, usaremos $* (todos # los parametros, te acuerdas?) y no $1. local Msg="$*" local !TamMsg=${#Msg} local Col=$(((!TotCols - !TamMsg) / 2)) # Centra mensaje en la linea tput cup $LineaMesg $Col echo "$Msg" read -n1 tput cup $LineaMesg $Col; tput el # Borra mensaje de la pantalla return # Sale de la función } # El cuerpo del programa propiamente dicho comienza aqui clear echo " Inclusión de Músicas !========= !== !======= Título del Álbun: | Este campo fue Pista: < creado solamente para | orientar como llenar Nombre de la Música: Intérprete:" # Pantalla montada con un único echo while true do tput cup 5 38; tput el # Posiciona y limpia linea read Albun [ ! "$Albun" ] && # Operador dió <ENTER> { Pregunta "Desea Terminar" s n [ $SN = "n" ] && continue # Ahora sólo verifico minúsculas clear; exit # Fin de la ejecución } grep -iq "^$Albun\^" musicas 2> /dev/null && { !MandaMsg Este álbun ya esta catastrado continue # Vuelve para leer otro álbun } Reg="$Albun^" # $Reg recibirá los datos de grabación elArtista= # Grabará artista anterior while true do ((Track++)) tput cup 7 38 echo $Track tput cup 9 38 # Posiciona para leer música read Musica [ "$Musica" ] || # Si el operador dio <ENTER>... { Pregunta "Fin de Álbun?" s n [ "$SN" = n ] && continue # Ahora solo prueba la minuscula break # Sale del loop para grabar datos } tput cup 11 38 # Posiciona para leer Artista [ "$elArtista" ]&& echo -n "($elArtista) " # Artista anterior es default read Artista [ "$Artista" ] && elArtista="$Artista" Reg="$Reg$elArtista~$Musica:" # Montando registro tput cup 9 38; tput el # Borra Musica de la pantalla tput cup 11 38; tput el # Borra Artista de la pantalla done echo "$Reg" >> musicas # Graba registro en el fin del archivo sort musicas -o musicas # Clasifica el archivo done%OUT_FIM% %TERMINAL_FIM% Fijate que la estructura del _script_esta como en el gráfico de abajo: <center> %TABLE{ databg="#ffffff" }% | Variables Globales | | Funciones | | Cuerpo del Programa | </center> Esta estructuración es debida a que el _Shell_ es un lenguaje interpretado y así el programa es leído de izquierda a derecha y de arriba para abajo. De esa forma, para que una variable sea vista simultáneamente por el _script_ *y* sus funciones, debe ser declarada (o inicializada) antes de cualquier otra cosa. Las funciones deben ser declaradas antes del cuerpo del programa propiamente dicho para que en el lugar en que el programador mencione su nombre, el interprete _Shell_ ya lo haya localizado antes y registrado que es una función. Una cosa muy útil en el uso de funciones es tratar de hacerlas lo más generales posible, de forma que sirvan para otras aplicaciones, sin necesidad de tener que reescribirlas. Esas dos que acabamos de ver tienen uso general, pues es dificil hallar un _script_ que tenga una entrada de datos por teclado que no use una rutina del tipo de la =MandaMsg= o no interaccione con el operador a través de algo parecido a =Pregunta=. Consejo de amigo: crea un archivo y cada función nueva que programes, añádela a este archivo. Así con el tiempo tendrás una bella biblioteca de funciones que te ahorrará mucho tiempo de programación. ---++ El comando source Fíjate si notas algo diferente en la salida del =ls= siguiente: %TERMINAL_INI% $ ls -la .bash_profile%OUT_INI% -rw-r--r-- 1 Julio unknown 4511 Mar 18 17:45 .bash_profile%OUT_FIM% %TERMINAL_FIM% No mires la respuesta y vuelve a prestar atención! De acuerdo, ya que no tienes paciencia para pensar y prefieres leer la respuesta, te voy a dar una pista: me parece que ya sabes que el .bash_profile es uno de los programas que son automáticamente "ejecutados" cuando tu te logeas (ARRGGHH! Odio este término). Ahora que te dí esta ayuda, mira nuevamente la salida del =ls= y dime que hay de diferente en ella. Como te dije el .bash_profile es "ejecutado" en el momento del logon y fíjate que no tiene ningúna prerrogativa de ejecución. Esto ocurre porque si tu lo ejecutaras como cualquier otro _script_ simple, cuando terminara su ejecución, todo el ambiente generado por él moriría junto con el _Shell_ en el cual fue ejecutado (te acuerdas que todos los _scripts_ son ejecutados en _subshells_, verdad?). Pues bien, es para cosas así que existe el comando =source=, también conocido por =.= (punto). Este comando hace que no sea creado un nuevo _Shell_ (un _subshell_) para ejecutar el programa que le es pasado como parámetro. Mejor un ejemplo que 10.000 palabras. Mira el =scriptiziño= siguiente: %TERMINAL_INI% $ cat script_bobo%OUT_INI% cd .. ls%OUT_FIM% %TERMINAL_FIM% Simplemente debería ir hacia el directório superior del directório actual. Vamos a ejecutar unos comandos que incluyen el script_bobo y vamos a analizar los resultados: %TERMINAL_INI% $ pwd%OUT_INI% /home/jneves%OUT_FIM% $ script_bobo%OUT_INI% jneves juliana paula silvie%OUT_FIM% $ pwd%OUT_INI% /home/jneves%OUT_FIM% %TERMINAL_FIM% Si yo mandé subir un directório, porque no subió? Subió sí! El _subshell_ que fue creado para ejecutar el _script_ subió y listó los directórios de los cuatro usuarios debajo del =/home=, solo que así que el _script_ acabó, el _subshell_ se fue al limbo y con él, todo el ambiente creado. Mira ahora como la cosa cambia: %TERMINAL_INI% $ source script_bobo%OUT_INI% jneves juliana paula silvie%OUT_FIM% $ pwd%OUT_INI% /home%OUT_FIM% $ cd -%OUT_INI% /home/jneves%OUT_FIM% $ . script_bobo%OUT_INI% jneves juliana paula silvie%OUT_FIM% $ pwd%OUT_INI% /home%OUT_FIM% %TERMINAL_FIM% Ahh! Ahora sí! Siendo pasado como parámetro del comando =source= o =.= (punto), el _script_ fue ejecutado en el _Shell_ corriente dejando en este, todo el ambiente creado. Ahora damos un _rewind_ hacia el inicio de la explicación sobre este comando. Un poco antes, hablamos del .bash_profile, y a estas alturas ya debes saber que su tarea es, inmediatamente después del _login_, dejar el ambiente de trabajo preparado para el usuário, y ahora entendemos que por eso es ejecutado usando esta construcción. Y ahora debes estarte preguntando, sólo sirve para eso este comando?, y yo te digo que sí, pero eso nos trae una cantidad de ventajas y una de las más usadas es tratar funciones como rutinas externas. Mira una forma diferente de hacer nuestro programa para incluir CDs en el archivo =musicas=: %TERMINAL_INI% $ cat musinc7%OUT_INI% #!/bin/bash # Registra CDs (versión7) # # Área de varibles globales !LinhaMesg=$((`tput lines` - 3)) # Línea que msgs serán dadas para operador !TotCols=$(tput cols) # Qtd colunas de la tela para encuadrar msgs # El cuerpo del programa propriamente dicho comienza aqui clear echo " Inclusión de Músicas !======== !== !======= Título do Álbum: | Este campo fue Pista: < creado solamente para | orientar como llenar Nombre de la Música: Intérprete:" # Pantalla montada con un único echo while true do tput cup 5 38; tput el # Posiciona y limpa línea read Album [ ! "$Album" ] && # Operador dió <ENTER> { source pergunta.func "Desea Terminar" s n [ $SN = "n" ] && continue # Ahora sólo verifico minúsculas clear; exit # Fin de la ejecución } grep -iq "^$Album\^" musicas 2> /dev/null && { . mandamsg.func Este álbum ya está catastrado continue # Vuelve para leer otro álbum } Reg="$Album^" # $Reg reciberá los datos de grabación oArtista= # Guardará artista anterior while true do ((Faixa++)) tput cup 7 38 echo $Faixa tput cup 9 38 # Posiciona para leer música read Musica [ "$Musica" ] || # Si el operador hubiese dado <ENTER>... { . pergunta.func "Fin del Álbum?" s n [ "$SN" = n ] && continue # Ahora sólo verifico minúsculas break # Sale del loop para grabar datos } tput cup 11 38 # Posiciona para leer Artista [ "$oArtista" ] && echo -n "($oArtista) " # Artista anter. é default read Artista [ "$Artista" ] && oArtista="$Artista" Reg="$Reg$oArtista~$Musica:" # Montando registro tput cup 9 38; tput el # Borra Musica de la pantalla tput cup 11 38; tput el # Borra Artista de la pantalla done echo "$Reg" >> musicas # Graba registro en el fin del archivo sort musicas -o musicas # Clasifica el archivo done%OUT_FIM% %TERMINAL_FIM% Ahora el programa disminuyo considerablemente de tamaño y las funciones fueron cambiadas por archivos externos llamados =pergunta.func= y =mandamsg.func=, que de esta forma, pueden ser llamados por cualquer otro programa y con eso, reutilizando su código. Por motivos meramente didácticos las ejecuciones de =pergunta.func= y =mandamsg.func= están siendo llamadas por =source= y por =.= (punto) indiscriminadamente, sin embargo, prefiero el =source= por ser más visible, lo que le da mayor legibilidad al código y facilita su manutención posteriormente. Mira ahora como quedaron estos dos archivos: %TERMINAL_INI% $ cat pergunta.func%OUT_INI% # La función recibe 3 parámetros en el siguiente orden: # $1 - Mensaje a ser enviado a la pantalla # $2 - Valor que sera aceptado como respuesta por defecto # $3 - El otro valor aceptado # Suponiendo que $1=Acepta?, $2=s y $3=n, en la línea # de abajo colocaría en Msg el valor "Acepta? (s/n)" Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" <nop>TamMsg=${#Msg} Col=$(((<nop>TotCols - <nop>TamMsg) / 2)) # Centra msg en la línea tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + <nop>TamMsg + 1)) read -n1 SN [ ! $SN ] && SN=$2 # Si esta vacía coloca default en SN echo $SN | tr A-Z a-z # La salida de SN será en minúscula tput cup $LinhaMesg $Col; tput el # Borra msg de la pantalla%OUT_FIM% $ cat mandamsg.func%OUT_INI% # La función recibe solamente un parámetro # con el mensaje que se desea exhibir, # para no obligar al programador a pasar # el msg entre comillas, usaremos $* (todos # los parámetro, recuerdas?) y no $1. Msg="$*" <nop>TamMsg=${#Msg} Col=$(((<nop>TotCols - <nop>TamMsg) / 2)) # Centra msg en la línea tput cup $LinhaMesg $Col echo "$Msg" read -n1 tput cup $LinhaMesg $Col; tput el # Borra msg de la pantalla%OUT_FIM% %TERMINAL_FIM% En ambos archivos, hice solamente dos cambios que veremos en las observaciones que siguen, sin embargo tengo tres observaciones más para hacer: 1. Las variables no están siendo declaradas como =local=, porque está es una directiva que solamente puede ser usada en el cuerpo de funciones y por consiguiente, estas variables permanecen en el ambiente del Shell, llenándolo de basura; 1. El comando =return= no está presente pero podría estarlo, sin alterar en nada la lógica, ya que sólo serviría para indicar un eventual error vía un código de retorno previamente establecido (por ejemplo =return 1=, =return 2=, ...), siendo que el =return= y =return 0= son idénticos y significan rutina ejecutada sin errores; 1. El comando que estamos acostumbrados a usar para generar código de retorno es el =exit=, pero la salida de una rutina externa no puede ser hecha de esta forma, porque por estar siendo ejecutada en el mismo _Shell_ que el _script_ llamador, el =exit= simplemente cerraría este _Shell_, terminando la ejecución de todo el _script_; 1. De donde surgió la variable _LinhaMesg_? Ella vino del _musinc7_, porque habia sido declarada antes de la llamada de las rutinas (sin olvidar que el _Shell_ que está interpretando el _script_ y estas rutinas, es el mismo para todos); 1. Si decidiste usar rutinas externas, no seas haragán, abunda en los comentarios (principalmente sobre el pasaje de los parámetros) para facilitar la manutención y su uso para otros programas en el futuro. - Bien, ahora ya tienes una cantidad de novedades para mejorar los _scripts_ que hicimos. Te acuerdas del programa =listartista= en el cual pasabas el nombre de un artista como parámetro y él devolvia sus músicas? Era así: %TERMINAL_INI% $ cat listartista%OUT_INI% #!/bin/bash # Dado un artista, muestra sus músicas # versión 2 if [ $# -eq 0 ] then echo Usted debería haber pasado al menos un parámetro exit 1 fi IFS=" :" for <nop>ArtMus in $(cut -f2 -d^ musicas) do echo "$ArtMus" | grep -i "^$*~" > /dev/null && echo $ArtMus | cut -f2 -d~ done%OUT_FIM% %TERMINAL_FIM% - Claro que me acuerdo!... - Entonces para afirmar los conceptos que te pasé, hazlo con la pantalla formateada, en _loop_, de forma que solamente termine cuando reciba un =<ENTER>= puro en el nombre del artista. Ahhh! Cuando la lista llegue a la antepenúltima línea de la pantalla, el programa deberá detenerse para que el operador pueda leerlas, o sea, imagina que la pantalla tenga 25 lineas. Cada 22 músicas listadas (cantidad de líneas menos 3) el programa aguardará a que el operador teclee algo para entonces continuar. Eventuales mensajes de error deben ser pasados usando la rutina =mandamsg.func= que acabamos de hacer. - Mozo, trae dos más, el mio con poca presión... Y no te olvides, cualquer duda o falta de compañia para tomar una cerveza o hasta para hablar mal de los políticos lo único que tienes que hacer es mandarme un e-mail para <a href="mailto:julio.neves@gmail.com?Subject=Dudas Conversas de bar botequim">julio.neves@gmail.com</a>. Voy aprovechar tambiém para mandar mi aviso publicitario: puedes decirle a los amigos que quien quiera hacer un curso nota diez de programación en _Shell_ que mande un e-mail para <a href="mailto:julio.neves@uniriotec.br?Subject=Curso de Shell con Julio Neves">julio.neves@uniriotec.br</a> para informarse. Gracias y hasta la <a href="https://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarConversa009">próxima</a> -- Main.HumbertoPina - 10 Jan 2007 -- Main.PatricioReich - 24 Nov 2006
E
dit
|
A
ttach
|
P
rint version
|
H
istory
: r9
<
r8
<
r7
<
r6
<
r5
|
B
acklinks
|
V
iew topic
|
M
ore topic actions
Topic revision: r9 - 06 Feb 2008 - 23:28:05 -
CollonsTorre
TWikiBar
Página Inicial
Últimas alterações
Índice
Procurar
Estatísticas de Uso
Aviso de Atualização
Configurações Gerais
Projeto Gráfico
Mapa do Site
Quem Somos
Registre-se
?
Regras de Formatação
Biblioteca Gráfica
?
Carinhas Gráficas
Webs Wiki-SL
Amadeu
Anapolivre
ArquivoLivre
Arte
BahiaSocial
BeaBa
BibliotecaLivre
Blogs
BrasilDigital
BrasilELivre
BSM
Ccsa
CESL
CoberturaWiki
Cooperativas
Curriculo
DarvinMarosin
DiaD
Dinamicoop
Economia
EconomiaSolidaria
EducacaoLivre
Ekaaty
Emacsbr
ENSL
Fatos
Festival3
Festival4
Flisol
Fmpb
Formatos
Foswikibr
FSM2005
GNOMEBR
GTTemario2004
GTWeb
Guialivre
HDC
Incubus
InkscapeBrasil
Jogos
KdeBR
KSP
LGM
LinuxStokDoc
Livros
Main
Mentores
MHHOB
MinuanoDigital
MoradiaECidadania
OlhosDagua
Olimpo
OLPC
OOPTQ
Papers
PCLivre
PentahoBrasil
Pessoas
Portal
Prefeituras
PSLAL
PSLBA
PSLBancarios
PSLBrasil
PSLGO
PSLMA
PSLMG
PSLMIP
PSLMT
PSLMulheres
PSLPI
PubFisl10
PubFisl7
PubFisl8
PubFisl9
QuilomboDoSopapo
RadioSL
RedeMesh
RedePopular
RobotWars
Sandbox
Saudelivre
Scribus
Sementes
Shakya
SLRJ
SoftwareLivreIrece
SoftwareLivreVS
SoLiSC
SuporteLivre
System
Telecentros
TeseSA
TextoLivre
TV
TWikiBar
TWikiPtbr
UNELivre
UNIMIX
VilaTorres
WebNordeste
WTRD2004
Este Menu
?skin=free
English
Español
Português brasileiro
Copyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding Wiki-SL?
Send feedback