You are here:
Wiki-SL
>
TWikiBar Web
>
BatePapos
>
TWikiBarPapo008
(01 Aug 2009,
BrSalgado
)
(raw view)
E
dit
A
ttach
---+!! Papo de botequim parte VIII --- %TOC% --- - E aê cara tudo bem? - Legal!, eu queria te mostrar o que fiz mas já sei que você vai querer molhar o bico primeiro né? - Só pra contrariar, hoje vou deixar você mostrar logo o seu "bacalho". Vai mostra aí o que você fez. - Poxa o exercício que você passou é muito grande. Veja só como eu resolvi: %TERMINAL_INI% $ cat musinc5%OUT_INI% #!/bin/bash # Cadastra CDs (versao 5) # clear <nop>LinhaMesg=$((`tput lines` - 3)) # Linha que msgs serão dadas para operador <nop>TotCols=$(tput cols) # Qtd colunas da tela para enquadrar msgs echo " Inclusao de Músicas !======== !== !======= Título do Álbum: | Este campo foi Faixa: < criado somente para | orientar o preenchimento Nome da Música: Intérprete:" # Tela montada com um único echo while true do tput cup 5 38; tput el # Posiciona e limpa linha read Album [ ! "$Album" ] && # Operador deu <ENTER> { Msg="Deseja Terminar? (S/n)" !TamMsg=${#Msg} Col=$(((!TotCols - !TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + !TamMsg + 1)) read -n1 SN tput cup $LinhaMesg $Col; tput el # Apaga msg da tela [ $SN = "N" -o $SN = "n" ] && continue # $SN é igual a N ou (-o) n? clear; exit # Fim da execução } grep "^$Album\^" musicas > /dev/null && { Msg="Este álbum já está cadastrado" !TamMsg=${#Msg} Col=$(((!TotCols - !TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" read -n1 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela continue # Volta para ler outro álbum } Reg="$Album^" # $Reg receberá os dados para gravação oArtista= # Variavel que guarda artista anterior while true do ((Faixa++)) tput cup 7 38 echo $Faixa tput cup 9 38 # Posiciona para ler musica read Musica [ "$Musica" ] || # Se o operador tiver dado <ENTER>... { Msg="Fim de Álbum? (S/n)" !TamMsg=${#Msg} Col=$(((!TotCols - !TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + !TamMsg + 1) read -n1 SN tput cup $LinhaMesg $Col; tput el # Apaga msg da tela [ "$SN" = N -o "$SN" = n ]&&continue # $SN é igual a N ou (-o) n? break # Sai do loop para gravar } tput cup 11 38 # Posiciona para ler Artista [ "$oArtista" ]&& echo -n "($oArtista) " # Artista anterior é default read Artista [ "$Artista" ] && oArtista="$Artista" Reg="$Reg$oArtista~$Musica:" # Montando registro tput cup 9 38; tput el # Apaga Musica da tela tput cup 11 38; tput el # Apaga Artista da tela done echo "$Reg" >> musicas # Grava registro no fim do arquivo sort musicas -0 musicas # Classifica o arquivo done%OUT_FIM% %TERMINAL_FIM% - É o programa tá legal, tá todo estruturadinho, mas gostaria de alguns poucos comentários sobre o que você fez: * Só para relembrar, as seguintes construções: =[ ! $Album ] &&= e =[ $Musica ] ||= representam a mesma coisa, isto é, no caso da primeira, o testamos se a variável =$Album= não (=!=) tem nada dentro, então (=&&=) ... Na segunda, testamos se =$Musica= tem dado, senão (=||=) ... * Se você reclamou do tamanho dele, é porque ainda não dei algumas dicas. Repare que a maior parte do _script_ é para dar mensagens centradas na penúltima linha da tela. Repare ainda que algumas mensagens pedem um S ou um N e outras são só de advertência. Seria o caso típico do uso de funções, que seriam escritas somente uma vez e chamada a execução de diversos pontos do _script_. Vou montar duas funções para resolver estes casos e vamos incorporá-las ao seu programa para ver o resultado final. ---++ Funções - Chico! Agora traz dois chopes, sendo um sem colarinho, para me dar inspiração. <verbatim> Pergunta () { # A função recebe 3 parâmetros na seguinte ordem: # $1 - Mensagem a ser dada na tela # $2 - Valor a ser aceito com resposta default # $3 - O outro valor aceito # Supondo que $1=Aceita?, $2=s e $3=n, a linha a # seguir colocaria em Msg o valor "Aceita? (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 msg na linha tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + TamMsg + 1)) read -n1 SN [ ! $SN ] && SN=$2 # Se vazia coloca default em SN echo $SN | tr A-Z a-z # A saída de SN será em minúscula tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da função } </verbatim> Como podemos ver, uma função é definida quando fazemos =nome_da_função ()= e todo o seu corpo está entre chaves (={}=). Assim como conversamos aqui no Boteco sobre passagem de parâmetros, as funções os recebem da mesma forma, isto é, são parâmetros posicionais (=$1, $2, ..., $n=) e todas as regras que se aplicam a passagem de parâmetros para programas, também valem para funções, mas é muito importante realçar que os parâmetros passados para um programa não se confundem com aqueles que este passou para suas funções. Isso significa, por exemplo, que o =$1= de um _script_ é diferente do =$1= de uma de suas funções Repare que as variáveis =$Msg=, =$TamMsg= e =$Col= são de uso restrito desta rotina, e por isso foram criadas como =local=. A finalidade disso é simplesmente para economizar memória, já que ao sair da rotina, elas serão devidamente detonadas da partição e caso não tivesse usado este artifício, permaneceriam residentes. A linha de código que cria =local Msg=, concatena ao texto recebido (=$1=) um abre parênteses, a resposta _default_ (=$2=) em caixa alta, uma barra, a outra resposta (=$3=) em caixa baixa e finaliza fechando o parênteses. Uso esta convenção para, ao mesmo tempo, mostrar as opções disponíveis e realçar a resposta oferecida como _default_. Quase ao fim da rotina, a resposta recebida (=$SN=) é passada para caixa baixa de forma que no corpo do programa não se precise fazer este teste. Veja agora como ficaria a função para dar uma mensagem na tela: <verbatim> function MandaMsg { # A função recebe somente um parâmetro # com a mensagem que se deseja exibir, # para não obrigar ao programador passar # a msq entre aspas, usaremos $* (todos # os parâmetro, lembra?) e não $1. local Msg="$*" local TamMsg=${#Msg} local Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" read -n1 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da função } </verbatim> Esta é uma outra forma de definir uma função: não a chamamos como no exemplo anterior usando uma construção com a sintaxe =nome_da_função ()=, mas sim como =function nome_da_função=. Quanto ao mais, nada difere da anterior, exceto que, como consta dos comentários, usamos a variável =$*= que como já sabemos é o conjunto de todos os parâmetros passados, para que o programador não precise usar aspas envolvendo a mensagem que deseja passar para a função. Para terminar com este blá-blá-blá vamos ver então as alterações que o programa necessita quando usamos o conceito de funções: %TERMINAL_INI% $ cat musinc6%OUT_INI% #!/bin/bash # Cadastra CDs (versao 6) # # Área de variáveis globais !LinhaMesg=$((`tput lines` - 3)) # Linha que msgs serão dadas para operador !TotCols=$(tput cols) # Qtd colunas da tela para enquadrar msgs # Área de funções Pergunta () { # A função recebe 3 parâmetros na seguinte ordem: # $1 - Mensagem a ser dada na tela # $2 - Valor a ser aceito com resposta default # $3 - O outro valor aceito # Supondo que $1=Aceita?, $2=s e $3=n, a linha # abaixo colocaria em Msg o valor "Aceita? (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 msg na linha tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + !TamMsg + 1)) read -n1 SN [ ! $SN ] && SN=$2 # Se vazia coloca default em SN echo $SN | tr A-Z a-z # A saída de SN será em minúscula tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da função } function !MandaMsg { # A função recebe somente um parâmetro # com a mensagem que se deseja exibir, # para não obrigar ao programador passar # a msq entre aspas, usaremos $* (todos # os parâmetro, lembra?) e não $1. local Msg="$*" local !TamMsg=${#Msg} local Col=$(((!TotCols - !TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" read -n1 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da função } # O corpo do programa propriamente dito começa aqui clear echo " Inclusao de Músicas !======== !== !======= Título do Álbum: | Este campo foi Faixa: < criado somente para | orientar o preenchimento Nome da Música: Intérprete:" # Tela montada com um único echo while true do tput cup 5 38; tput el # Posiciona e limpa linha read Album [ ! "$Album" ] && # Operador deu <ENTER> { Pergunta "Deseja Terminar" s n [ $SN = "n" ] && continue # Agora só testo a caixa baixa clear; exit # Fim da execução } grep -iq "^$Album\^" musicas 2> /dev/null && { !MandaMsg Este álbum já está cadastrado continue # Volta para ler outro álbum } Reg="$Album^" # $Reg receberá os dados de gravação oArtista= # Guardará artista anterior while true do ((Faixa++)) tput cup 7 38 echo $Faixa tput cup 9 38 # Posiciona para ler musica read Musica [ "$Musica" ] || # Se o operador tiver dado <ENTER>... { Pergunta "Fim de Álbum?" s n [ "$SN" = n ] && continue # Agora só testo a caixa baixa break # Sai do loop para gravar dados } tput cup 11 38 # Posiciona para ler Artista [ "$oArtista" ]&& echo -n "($oArtista) " # Artista anterior é default read Artista [ "$Artista" ] && oArtista="$Artista" Reg="$Reg$oArtista~$Musica:" # Montando registro tput cup 9 38; tput el # Apaga Musica da tela tput cup 11 38; tput el # Apaga Artista da tela done echo "$Reg" >> musicas # Grava registro no fim do arquivo sort musicas -o musicas # Classifica o arquivo done%OUT_FIM% %TERMINAL_FIM% Repare que a estruturação do _script_ está conforme o gráfico a seguir: <center> %TABLE{ databg="#ffffff" }% | Variáveis Globais | | Funções | | Corpo do Programa | </center> Esta estruturação é devido ao _Shell_ ser uma linguagem interpretada e desta forma o programa é lido da esquerda para a direita e de cima para baixo e uma variável para ser vista simultaneamente pelo _script_ *e* suas funções deve ser declarada (ou inicializada) antes de qualquer coisa. As funções por sua vez devem ser declaradas antes do corpo do programa propriamente dito porque no ponto em que o programador mencionou seu nome, o interpretador _Shell_ já o havia antes localizado e registrado que era uma função. Uma coisa bacana no uso de funções é fazê-las o mais genérico possível de forma que elas sirvam para outras aplicações, sem necessidade de serem reescritas. Essas duas que acabamos de ver têm uso generalizado, pois é difícil um _script_ que tenha uma entrada de dados pelo teclado que não use uma rotina do tipo da =MandaMsg= ou não interage com o operador por algo semelhante à =Pergunta=. Conselho de amigo: crie um arquivo e cada função nova que você criar, anexe-a a este arquivo. Ao final de um tempo você terá uma bela biblioteca de funções que lhe poupará muito tempo de programação. ---++ O comando source Vê se você nota algo de diferente na saída do =ls= a seguir: %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% Não olhe a resposta não, volte a prestar atenção! Bem, já que você está mesmo sem saco de pensar e prefere ler a resposta, vou te dar uma dica: acho que você sabe que o .bash_profile é um dos programas que são automaticamente "executados" quando você se loga (ARRGGHH! Odeio este termo). Agora que te dei esta dica olhe novamente para a saída do =ls= e me diga o que há de diferente nela. Como eu disse o .bash_profile é "executado" em tempo de logon e repare que não tem nenhum direito de execução. Isso se dá porque o se você o executasse como qualquer outro _script_ careta, quando terminasse sua execução todo o ambiente por ele gerado morreria junto com o _Shell_ sob o qual ele foi executado (você se lembra que todos os _scripts_ são executados em _subshells_, né?). Pois é. É para coisas assim que existe o comando =source=, também conhecido por =.= (ponto). Este comando faz com que não seja criado um novo _Shell_ (um _subshell_) para executar o programa que que lhe é passado como parâmetro. Melhor um exemplo que 453 palavras. Veja este _scriptizinho_ a seguir: %TERMINAL_INI% $ cat script_bobo%OUT_INI% cd .. ls%OUT_FIM% %TERMINAL_FIM% Ele simplesmente deveria ir para o diretório acima do diretório atual. Vamos executar uns comandos envolvendo o script_bobo e vamos analisar os 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% Se eu mandei ele subir um diretório, porque não subiu? Subiu sim! O _subshell_ que foi criado para executar o _script_ tanto subiu que listou os diretórios dos quatro usuários abaixo do =/home=, só que assim que o _script_ acabou, o _subshell_ foi para o beleleu e com ele todo o ambiente criado. Olha agora como a coisa muda: %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! Agora sim! Sendo passado como parâmetro do comando =source= ou =.= (ponto), o _script_ foi executado no _Shell_ corrente deixando neste, todo o ambiente criado. Agora damos um _rewind_ para o início da explicação sobre este comando. Lá falamos do .bash_profile, e a esta altura você já deve saber que a sua incumbência é, logo após o _login_, deixar o ambiente de trabalho preparado para o usuário, e agora entendemos que é por isso mesmo que ele é executado usando este artifício. E agora você deve estar se perguntando se é só para isso que este comando serve, e eu lhe digo que sim, mas isso nos traz um monte de vantagens e uma das mais usadas é tratar funções como rotinas externas. Veja uma outra forma de fazer o nosso programa para incluir CDs no arquivo =musicas=: %TERMINAL_INI% $ cat musinc7%OUT_INI% #!/bin/bash # Cadastra CDs (versao 7) # # Área de variáveis globais !LinhaMesg=$((`tput lines` - 3)) # Linha que msgs serão dadas para operador !TotCols=$(tput cols) # Qtd colunas da tela para enquadrar msgs # O corpo do programa propriamente dito começa aqui clear echo " Inclusao de Músicas !======== !== !======= Título do Álbum: | Este campo foi Faixa: < criado somente para | orientar o preenchimento Nome da Música: Intérprete:" # Tela montada com um único echo while true do tput cup 5 38; tput el # Posiciona e limpa linha read Album [ ! "$Album" ] && # Operador deu <ENTER> { source pergunta.func "Deseja Terminar" s n [ $SN = "n" ] && continue # Agora só testo a caixa baixa clear; exit # Fim da execução } grep -iq "^$Album\^" musicas 2> /dev/null && { . mandamsg.func Este álbum já está cadastrado continue # Volta para ler outro álbum } Reg="$Album^" # $Reg receberá os dados de gravação oArtista= # Guardará artista anterior while true do ((Faixa++)) tput cup 7 38 echo $Faixa tput cup 9 38 # Posiciona para ler musica read Musica [ "$Musica" ] || # Se o operador tiver dado <ENTER>... { . pergunta.func "Fim de Álbum?" s n [ "$SN" = n ] && continue # Agora só testo a caixa baixa break # Sai do loop para gravar dados } tput cup 11 38 # Posiciona para ler 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 # Apaga Musica da tela tput cup 11 38; tput el # Apaga Artista da tela done echo "$Reg" >> musicas # Grava registro no fim do arquivo sort musicas -o musicas # Classifica o arquivo done%OUT_FIM% %TERMINAL_FIM% Agora o programa deu uma boa encolhida e as chamadas de função foram trocadas por arquivos externos chamados =pergunta.func= e =mandamsg.func=, que assim podem ser chamados por qualquer outro programa, desta forma reutilizando o seu código. Por motivos meramente didáticos as execuções de =pergunta.func= e =mandamsg.func= estão sendo comandadas por =source= e por =.= (ponto) indiscriminadamente, embora prefira o =source= por ser mais visível desta forma dando maior legibilidade ao código e facilitando sua posterior manutenção. Veja agora como ficaram estes dois arquivos: %TERMINAL_INI% $ cat pergunta.func%OUT_INI% # A função recebe 3 parâmetros na seguinte ordem: # $1 - Mensagem a ser dada na tela # $2 - Valor a ser aceito com resposta default # $3 - O outro valor aceito # Supondo que $1=Aceita?, $2=s e $3=n, a linha # abaixo colocaria em Msg o valor "Aceita? (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 na linha tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + <nop>TamMsg + 1)) read -n1 SN [ ! $SN ] && SN=$2 # Se vazia coloca default em SN echo $SN | tr A-Z a-z # A saída de SN será em minúscula tput cup $LinhaMesg $Col; tput el # Apaga msg da tela%OUT_FIM% $ cat mandamsg.func%OUT_INI% # A função recebe somente um parâmetro # com a mensagem que se deseja exibir, # para não obrigar ao programador passar # a msq entre aspas, usaremos $* (todos # os parâmetro, lembra?) e não $1. Msg="$*" <nop>TamMsg=${#Msg} Col=$(((<nop>TotCols - <nop>TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" read -n1 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela%OUT_FIM% %TERMINAL_FIM% Em ambos os arquivos, fiz somente duas mudanças que veremos nas observações a seguir, porém tenho mais três a fazer: 1. As variáveis não estão sendo mais declaradas como =local=, porque está é uma diretiva que só pode ser usada no corpo de funções e portanto estas variáveis permanecem no ambiente do Shell, poluindo-o; 1. O comando =return= não está mais presente mas poderia estar sem alterar em nada a lógica, uma vez que ele só serviria para indicar um eventual erro via um código de retorno previamente estabelecido (por exemplo =return 1=, =return 2=, ...), sendo que o =return= e =return 0= são idênticos e significam rotina executada sem erros; 1. O comando que estamos acostumados a usar para gerar código de retorno é o =exit=, mas a saída de uma rotina externa não pode ser feita desta forma, porque por estar sendo executada no mesmo _Shell_ que o _script_ chamador, o =exit= simplesmente encerraria este _Shell_, terminando a execução de todo o _script_; 1. De onde surgiu a variável _LinhaMesg_? Ela veio do _musinc7_, porque ela havia sido declarada antes da chamada das rotinas (nunca esquecendo que o _Shell_ que está interpretando o _script_ e estas rotinas é o mesmo); 1. Se você decidir usar rotinas externas, não se avexe, abunde os comentários (principalmente sobre a passagem dos parâmetros) para facilitar a manutenção e seu uso por outros programas no futuro. - Bem, agora você já tem mais um monte de novidade para melhorar os _scripts_ que fizemos você se lembra do programa =listartista= no qual você passava o nome de um artista como parâmetro e ele devolvia as suas músicas? Ele era assim: %TERMINAL_INI% $ cat listartista%OUT_INI% #!/bin/bash # Dado um artista, mostra as suas musicas # versao 2 if [ $# -eq 0 ] then echo Voce deveria ter passado pelo menos um parametro 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 lembro!... - Então para firmar os conceitos que te passei, faça ele com a tela formatada, em _loop_, de forma que ele só termine quando receber um =<ENTER>= puro no nome do artista. Ahhh! Quando a listagem atingir a antepenúltima linha da tela, o programa deverá dar uma parada para que o operador possa lê-las, isto é, suponha que a tela tenha 25 linhas. A cada 22 músicas listadas (quantidade de linhas menos 3) o programa aguardará que o operador tecle algo para então prosseguir. Eventuais mensagens de erro devem ser passadas usando a rotina =mandamsg.func= que acabamos de desenvolver. - Chico, manda mais dois, o meu é com pouca pressão... Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em _Shell_ que mande um e-mail para a nossa <a href="mailto:contato@clavis.com.br?Subject=Curso de Shell com Julio Neves">gerencia de treinamento</a> para informar-se. Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=Dúvidas Papo de Botequim">mim</a>. Valeu!
E
dit
|
A
ttach
|
P
rint version
|
H
istory
: r15
<
r14
<
r13
<
r12
<
r11
|
B
acklinks
|
V
iew topic
|
M
ore topic actions
Topic revision: r15 - 01 Aug 2009 - 22:33:36 -
BrSalgado
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