Script Muuuuuito lento

1. Script Muuuuuito lento

Marcio
mazinatti

(usa Antergos)

Enviado em 17/04/2018 - 18:25h

Boa Noite pessoa!

Estou fazendo um script para trabalhar aruivos txt que estão dentro de uma pasta.. Mas a saida do script esta muito lento em arquivos com 50000 linhas"cada linhas contem apenas uma palavra" demora ate 2 horas para terminar de rodar.

Segue oque estou fazendo.. jah tentei varias maneiras de saida, mas nada.


#!/bin/bash
#################################################

i=100

#listo o Diretório e coloco em um array todos os arquivo TXT
lista=(`ls *.txt`)

echo "existem ${#lista} Arquivos em formato *txt na pasta \n" `ls *.txt`

for ((N=0;N<${#lista[*]};N++));do

#Crio os arquivos temporários
echo > $i

#faço uma cópia do arquivo original
cp ${lista[N]} $N

#Verifico se o arquivo possui algum conteudo
if [ -s "${lista[N]}" ]; then

arrayS=( $(cat $N) )

for ((M=0;M<${#arrayS[*]};M++));do

Maiuscula=$(echo ${arrayS[M]} | awk '{ print toupper($0); }')
Minuscula=$(echo ${arrayS[M]} | awk '{ print tolower($0); }') #Todas as letras minusculas
PMaiuscula=$(echo $Minuscula | sed 's/(\b.)/\U&/g') #A primeira letra Sempre Maiuscula

echo ${Maiuscula} >> $i
echo ${Minuscula} >> $i
echo ${PMaiuscula} >> $i
done

sed -i "s/ //g" $i

rm $criaCam1
rm $N

let i=i+1

else
echo "Arquivo ${lista[N]} Esta Vazio"
fi
done



  


2. Re: Script Muuuuuito lento

Marcelo Oliver
msoliver

(usa Debian)

Enviado em 17/04/2018 - 20:01h

mazinatti escreveu:

Boa Noite pessoa!

Estou fazendo um script para trabalhar aruivos txt que estão dentro de uma pasta.. Mas a saida do script esta muito lento em arquivos com 50000 linhas"cada linhas contem apenas uma palavra" demora ate 2 horas para terminar de rodar.

Segue oque estou fazendo.. jah tentei varias maneiras de saida, mas nada.


#!/bin/bash
#################################################

i=100

#listo o Diretório e coloco em um array todos os arquivo TXT
lista=(`ls *.txt`)

echo "existem ${#lista} Arquivos em formato *txt na pasta \n" `ls *.txt`

for ((N=0;N<${#lista[*]};N++));do

#Crio os arquivos temporários
echo > $i

#faço uma cópia do arquivo original
cp ${lista[N]} $N

#Verifico se o arquivo possui algum conteudo
if [ -s "${lista[N]}" ]; then

arrayS=( $(cat $N) )

for ((M=0;M<${#arrayS[*]};M++));do

Maiuscula=$(echo ${arrayS[M]} | awk '{ print toupper($0); }')
Minuscula=$(echo ${arrayS[M]} | awk '{ print tolower($0); }') #Todas as letras minusculas
PMaiuscula=$(echo $Minuscula | sed 's/(\b.)/\U&/g') #A primeira letra Sempre Maiuscula

echo ${Maiuscula} >> $i
echo ${Minuscula} >> $i
echo ${PMaiuscula} >> $i
done

sed -i "s/ //g" $i

rm $criaCam1
rm $N

let i=i+1

else
echo "Arquivo ${lista[N]} Esta Vazio"
fi
done


Boa noite mazinatti.
Vamos ver se entendi corretamente o seu script . . .
O objetivo é criar um arquivo para cada original, contendo :
Maiúscula
Minuscula
Primeira letra maiúscula
É isso?

Marcelo Oliver



3. Re: Script Muuuuuito lento

Marcio
mazinatti

(usa Antergos)

Enviado em 17/04/2018 - 21:55h

Boa noite Marcelo,
Nesse exemplo sim, mas trabalharei com mais variaveis assim que descobri o motivo que esta fazendo o script ficar tãaao lento... Sei que trabalho com string deixa o script lento, entretanto, nesse caso, esta lentoo demais.


4. Re: Script Muuuuuito lento

Marcelo Oliver
msoliver

(usa Debian)

Enviado em 17/04/2018 - 22:47h

mazinatti escreveu:

Boa noite Marcelo,
Nesse exemplo sim, mas trabalharei com mais variaveis assim que descobri o motivo que esta fazendo o script ficar tãaao lento... Sei que trabalho com string deixa o script lento, entretanto, nesse caso, esta lentoo demais.


Boa noite Mazzinati.
Ao invés de criar um array com todos arquivo,
Crie um txt, exemplo:
ls *.txt >>lista.txt
Depois faça um laço com o while, onde o while vai ler linha por linha, tendo assim o nome de cada arquivo.
exemplo:
while read line;do
#Ações/Comandos para executar
done<lista.txt


marcelo oliver



5. Re: Script Muuuuuito lento

Marcio
mazinatti

(usa Antergos)

Enviado em 17/04/2018 - 23:09h

Marcelo, muito obrigado pela dica.. vou testar e volto com uma resposta.. mesmo assim.. Muito Obrigado.


6. Re: Script Muuuuuito lento


oxidante

(usa Debian)

Enviado em 18/04/2018 - 06:14h

A causa da lentidão é que teu código está chamando awk/sed para cada linha lida do arquivo. Uma solução é passar o arquivo inteiro para os comandos awk/sed e salvar seus resultados nas variáveis MAIUSC, MINUSC e PMAIUSC como arrays. Após isso, crie um loop para ler desses arrays e salvar para o arquivo de destino. O código abaixo faz isso e o processamento termina em 38s para 1 arquivo txt de 50 mil linhas (testado em processador de 1 núcleo de 800Mhz). Creio que dê para otimizar mais ainda, evitando as múltiplas escritas, elemento por elemento, dos arrays para o arquivo. Quem sabe alguns colegas do fórum possam melhorá-lo.


i=100; for infile in *.txt; do MAIUSC=($(awk '{print toupper($0)}' $infile)); MINUSC=($(awk '{print tolower($0)}' $infile)); PMAIUSC=($(sed 's/./\U&/' $infile)); for((j=0;j<${#MAIUSC[*]};j++)); do echo -e "${MAIUSC[j]}\n${MINUSC[j]}\n${PMAIUSC[j]}\n" >> $i; done; let i=i+1; done



7. Re: Script Muuuuuito lento

Paulo
paulo1205

(usa Ubuntu)

Enviado em 18/04/2018 - 15:08h

Se o script roda essencialmente comandos do awk, por que não fazer todo ele em awk (ou Perl)? Mesmo sem testar, eu tenho certeza de que vai ser mais eficiente.


8. Re: Script Muuuuuito lento

Paulo
paulo1205

(usa Ubuntu)

Enviado em 18/04/2018 - 18:22h

Processando 100 arquivos com 50000 cada (5 milhõs de linhas no total), por meio de um script em Perl, eis o resultado (num Core i5 650, 3.2GHz, e com Chrome, Firefox, VMware Player com duas vCPUs roando Windows 7, LibreOffice Calc e um cliente de e-mail corporativo em Java rodando ao mesmo tempo):
time ./proc.pl 

real 0m13.187s
user 0m12.920s
sys 0m0.248s

(Ou seja, uma média de cerca de 0,132 por cada arquivo de 50000 linhas.)

Eis o código do script.
#!/usr/bin/perl

$i=100;
foreach $file (<*.txt>){
die("Erro ao abrir arquivo de entrada '$file'.") unless open(IN, "<$file");
die("Erro ao abrir arquivo de saída '$i'.") unless open(OUT, ">$i");
print OUT "\n"; # Equivalente a “echo > $i”.
if(-s IN){
while(<IN>){
$mai=uc($_);
$pmai=$min=lc($_);
$pmai=~s/\b./uc($&)/eg;
$mai=~s/ +//;
$min=~s/ +//;
$pmai=~s/ +//;
print OUT $mai, $min, $pmai;
}
}
else{
print "Arquivo '$file' está vazio.\n";
}
close(IN);
close(OUT);
$i++;
}



9. Re: Script Muuuuuito lento

Paulo
paulo1205

(usa Ubuntu)

Enviado em 19/04/2018 - 02:46h

Em casa, com um A10-6800K 2GHz, com micro relativamente ocioso, o mesmo programa acima processou os mesmos 100 arquivos com 50000 em cada um pouquinho mais rápido que o micro do trabalho.
/usr/bin/time -f "%U user\n%S sys\n%E elapsed\n%P CPU usage\n%M kiB max" ./proc.pl 
10.78 user
0.30 sys
0:11.09 elapsed
99% CPU usage
2720 kiB max

(Ou seja: 0,119 segundo por arquivo de 50k linhas.)

Sabendo que dava para ser mais rápido, adaptei o programa para C++, sem usar expressões regulares, de modo que, compilado com opção de otimização (-O3), rodou com os seguintes tempos.
/usr/bin/time -f "%U user\n%S sys\n%E elapsed\n%P CPU usage\n%M kiB max" ./proc-c++
1.69 user
0.26 sys
0:01.98 elapsed
98% CPU usage
1488 kiB max

(Ou seja: menos de dois centésimos de segundo por arquivo de 50k linhas.)

#include <fstream>
#include <iostream>
#include <string>

#include <boost/filesystem.hpp>

using namespace std;
using namespace boost::filesystem;

int main(){
unsigned i=100;
for(directory_iterator file("."); file!=directory_iterator(); file++){
string filename(file->path().string());
if(filename.substr(filename.size()-4)!=".txt")
continue;
ifstream in(filename, ios::ate);
ofstream out(to_string(i));
out << '\n';
if(in.tellg()!=0){
in.seekg(0);
string line;
while(getline(in, line)){
for(unsigned char c: line){
c=toupper(c);
if(c!=' ')
out.put(c);
}
out.put('\n');
for(unsigned char c: line){
c=tolower(c);
if(c!=' ')
out.put(c);
}
out.put('\n');
bool next_is_upper=true;
for(unsigned char c: line){
c=next_is_upper? toupper(c): tolower(c);
next_is_upper=!isalnum(c);
if(c!=' ')
out.put(c);
}
out.put('\n');
}
}
else
cout << "Arquivo '" << filename << "' está vazio.\n";

i++;
}
}


Certamente ainda é possível fazer uma versão mais rápida e usando menos memória (por exemplo, usando opendir()/readdir()/closedir() em lugar de boost::filesystem::directory_iterator, vetores nativos de caracteres em lugar de std::string e FILE * em lugar de std::ifstream e std::ofstream), mas o programa ficaria possivelmente menos portável (que eu me lembre, o Windows não tem opendir()/readdir()/closedir(), e seria preciso usar os equivalentes nativos desse sistema para poder ter o programa rodando nele).


10. Re: Script Muuuuuito lento

Paulo
paulo1205

(usa Ubuntu)

Enviado em 19/04/2018 - 04:00h

Uma versão em C, não muito burilada. Marginalmente mais rápida que a versão em C++, mas consumindo muito menos memória.
/usr/bin/time -f "%U user\n%S sys\n%E elapsed\n%P CPU usage\n%M kiB max" ./proc-c
1.67 user
0.09 sys
0:01.78 elapsed
98% CPU usage
692 kiB max


#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <dirent.h> // Unix
#include <sys/types.h> // Unix

const char work_dir[]=".";
unsigned char line[1024];

int main(void){
unsigned i=100;
DIR *dir;
if(!(dir=opendir(".")))
return 1;
struct dirent *entry;
while((entry=readdir(dir))!=NULL){
char filename[PATH_MAX];
int name_len=snprintf(filename, sizeof filename, "%s/%s", work_dir, entry->d_name);
if(strcmp(filename+name_len-4, ".txt")!=0)
continue;
FILE *in, *out;
in=fopen(filename, "r");
if(!in)
continue;
char i_str[PATH_MAX];
snprintf(i_str, sizeof i_str, "%u", i);
out=fopen(i_str, "w");
if(!out){
fclose(in);
continue;
}
putc('\n', out);
if(fseek(in, 0, SEEK_END)==0 && ftell(in)!=0){
fseek(in, 0, SEEK_SET);
while(fgets((char *)line, sizeof line, in)){
for(unsigned char *p=line; *p; p++){
int c=toupper(*p);
if(c!=' ')
putc(c, out);
}
for(unsigned char *p=line; *p; p++){
int c=tolower(*p);
if(c!=' ')
putc(c, out);
}
bool next_is_upper=true;
for(unsigned char *p=line; *p; p++){
int c=next_is_upper? toupper(*p): tolower(*p);
next_is_upper=!isalnum(c);
if(c!=' ')
putc(c, out);
}
}
}
else
fprintf(stderr, "Arquivo '%s' está vazio.\n", filename);

fclose(out);
fclose(in);

i++;
}
closedir(dir);

return 0;
}



11. Re: Script Muuuuuito lento

Marcio
mazinatti

(usa Antergos)

Enviado em 19/04/2018 - 22:19h

Boa Noite Senhores..
Tente cada um dos métodos colocado aqui.. o mais rápido foi o perl, entretanto eu nao sei "ainda" trabalhar com o perl.. então resolvi o problema com o cat.. leio agora o arquivo inteiro e vou salvando em um arquivo novo jah formatado.


#!/bin/bash

criaCam1="1MAIUSC"
criaCam2="1minusc"
criaCam3="1Pmaiusc"
criaCam4="1VtUdOm"
criaCam5="1VTuMiN"

i=100

#Sempre que rodo limpa os arquivos antigos
echo > $criaCam1
echo > $criaCam2
echo > $criaCam3
echo > $criaCam4
echo > $criaCam5
lista=(`ls *.txt`)

sort $lista

echo "existem ${#lista} Arquivos em formato *txt na pasta" `ls *.txt`

for ((N=0;N<${#lista[*]};N++));do

#faço uma cópia do arquivo original
cp ${lista[N]} $N

#Verifico se o arquivo possui algum conteudo
if [ -s "${lista[N]}" ]
then

#Aviso com qual arquivo vou trabalhar
echo 'Trabalho o arquivo '${lista[N]}' agora com '`wc -l ${lista[N]}` 'linhas'

Maiuscula=$(cat ${N} | awk '{ print toupper($0); }') #todas as letras carregadas maiusculas
Minuscula=$(cat ${N} | awk '{ print tolower($0); }') #Todas as letras minusculas
PMaiuscula=$(echo $Minuscula | sed 's/(\b.)/\U&/g') #A primeira letra Sempre Maiuscula


echo $Maiuscula >> $criaCam1
echo $Minuscula >> $criaCam2
echo $PMaiuscula >> $criaCam3


fi
rm $N
let i=i+1
done


Desde já.

Muito Obrigados a todos que me ajudaram..


12. Re: Script Muuuuuito lento

Paulo
paulo1205

(usa Ubuntu)

Enviado em 23/04/2018 - 22:42h

mazinatti escreveu:

Boa Noite Senhores..
Tente cada um dos métodos colocado aqui.. o mais rápido foi o perl, entretanto eu nao sei "ainda" trabalhar com o perl.. então resolvi o problema com o cat.. leio agora o arquivo inteiro e vou salvando em um arquivo novo jah formatado.


Bem, eu acho Perl tranquilo porque em muito ele lembra outra ferramentas comuns, como se fosse uma mistura de shell, awk, grep e sed. De todo modo, a escolha cabe a você, obviamente.

Permita-me fazer alguns comentários no seu código.

#!/bin/bash

criaCam1="1MAIUSC"
criaCam2="1minusc"
criaCam3="1Pmaiusc"
criaCam4="1VtUdOm"
criaCam5="1VTuMiN"

i=100

#Sempre que rodo limpa os arquivos antigos
echo > $criaCam1
echo > $criaCam2
echo > $criaCam3
echo > $criaCam4
echo > $criaCam5


Na verdade, o que você faz nas linhas cima é colocar uma linha em branco e cada um desses arquivos. Se seu objetivo é remover conteúdo anterior, troque o comando echo pelo comando : (apenas o sinal de “:”, que é um comando que não faz nada), ou não coloque comando nenhum, apenas o redirecionamento.

lista=(`ls *.txt`) 


Isso pode ser problemático se:

  • houver arquivos cujos nomes contenham espaços, tabulações ou quebras de linha;

  • houver muitos arquivos, pois vai consumir muita memória do processo que está rodando o script;

  • não houver nenhum arquivo na forma *.txt (com as configurações mais comuns, isso ocasionaria erro no shell ou por parte de ls[);

  • a lista for vazia (dependeria de preparar o shell para não cair no caso anterior, mas tem seus próprios impactos, especialmente neste seu script, conforme discutido mais abaixo).

Não bastassem esses problemas condicionais, você chama ls inutilmente, uma vez que é o próprio shell que expande o padrão “*.txt”.

Seria mais simples e eficiente fazer simplesmente “lista=( *.txt )”, e isso ainda teria o benefício adicional de evitar o problema de arquivos com nomes contendo espaços. Infelizmente, isso não resolve o gasto de memória provocado por uma eventual lista gigantesca de arquivos (mesmo em princípio preferindo evitar comandos externos, quando eu não necessariamente tenho controle sobre a quantidade de arquivos a ser processada, eu prefiro não trazer toda a lista para a memória de uma só vez, e mais abaixo eu mostrou um jeito de assim fazer).

Para preparar o shell para a possibilidade de não haver nenhum arquivo com sufixo “.txt”, o certo seria executar anteriormente os seguintes comandos (que se aplicam tanto ao uso que você fez de ls quanto à forma alternativa que lhe sugiro).

set +o noglob
shopt -u failglob
shopt -s nullglob


sort $lista 


Qual a utilidade desse comando? Porque o que ele faz é mostrar na saída padrão o conteúdo do primeiro elemento da lista, só que de forma ordenada. Se você rodar o script no terminal, a saída será na tela. Tem certeza de que é isso que você quer?

Mas mais problemático ainda é quando o conteúdo de lista é vazio (o terceiro caso da observação anterior). Nessa situação, o comando sort vai esperar que os dados a serem ordenados venham da entrada padrão. Se for executado no terminal, o script vai esperar que você digite tal conteúdo. Tenho quase certeza de que você não quer que isso aconteça.

echo "existem ${#lista} Arquivos em formato *txt na pasta" `ls *.txt` 


Se você já tem a lista, para que rodar novamente o comando ls? Você poderia conseguir o mesmo efeito com algo como “echo "..." *.txt” ou “echo "... $lista[*]"”.

Contudo, fica a pergunta: você precisa realmente exibir a lista?

for ((N=0;N<${#lista[*]};N++));do 


Impressão da mensagem à parte, e ignorando a ordenação do primeiro arquivo, que me pareceu um acidente de percurso, uma forma mais segura iterar sobre os elementos da lista de arquivos seria a seguinte.

# Roda o comando find no diretório corrente (.), utilizando um byte nulo como separador
# de nomes (pois é possível teoricamente ter um arquivo com quebra de linha no meio do nome)
# e joga a saída no file descriptor de nº 3, redirecionado-o como fd de entrada de dados.
exec 3< <(find . -maxdepth1 -iname "*.txt" -print0)

# N deixa de ser uma variável de controle da iteração, e passa a ser incrementada manualmente.
N=0

# Itera pelos dados recebidos do find, mandando ler do descritor 3 (-u 3) e usar
# o byte nulo como separador dos registros (-d $'\0').
while read -u 3 -d $'\0' arquivo; do


Dentro do bloco a ser repetido, em lugar de “${lista[N]}” você usaria “"$arquivo"”.

#faço uma cópia do arquivo original 
cp ${lista[N]} $N


Para que essa cópia? Depois você vai apagá-la, e você não mexe nos arquivos originais. Assim sendo, você poderia usar os arquivos originais como base para as transformações que quisesse fazer.

#Verifico se o arquivo possui algum conteudo
if [ -s "${lista[N]}" ]
then


Você não deveria ter feito essa verificação antes de copiar o arquivo (supondo que você tenha mesmo de copiá-lo, que não parece ser o caso)?

	    #Aviso com qual arquivo vou trabalhar
echo 'Trabalho o arquivo '${lista[N]}' agora com '`wc -l ${lista[N]}` 'linhas'

Maiuscula=$(cat ${N} | awk '{ print toupper($0); }') #todas as letras carregadas maiusculas
Minuscula=$(cat ${N} | awk '{ print tolower($0); }') #Todas as letras minusculas
PMaiuscula=$(echo $Minuscula | sed 's/(\b.)/\U&/g') #A primeira letra Sempre Maiuscula


Para os dois primeiros, se o objetivo é somente converte de maiúsculas para minúsculas, em vez de awk você poderia usar tr, que é potencialmente mais simples e mais leve. E não precisaria de dois programas externos (cat ... | awk ...), mas apenas de um deles, como no exemplo abaixo.

Maiuscula=$(tr '[:lower:]' '[:upper:]' < "$arquivo")
Minuscula=$(tr '[:upper:]' '[:lower:]' < "$arquivo")


Note que eu coloco “"$arquivo"”, com a expansão da variável entre aspas, porque o nome do arquivo pode conter espaços asteriscos e outras coisas perigosas.

Contudo, eu, novamente, desaprovo essa ideia de ler todo o conteúdo para a memória de uma vez só (e triplicado, ainda por cima), porque você pode topar com um arquivo gigantesco, que pode comprometer a execução do seu programa (ou até mesmo do sistema!) ao consumir toda a memória que ele tem disponível.



echo $Maiuscula >> $criaCam1
echo $Minuscula >> $criaCam2
echo $PMaiuscula >> $criaCam3


Seu código de agora é bem diferente do que você mostrou originalmente. Antes, cada arquivo da lista de arquivos de entrada gerava um arquivo de saída, e cada palavra transformada ocupava um linha distinta nesse arquivo de saída. Neste de agora, você gera apenas três arquivos, cada um deles contendo uma linha para cada arquivo de entrada, com todas as palavras transformads de cada arquivo numa só linha.

Os dois programas só guardam relação pelas transformações feitas sobre cada palavra, mas a disposição de saída de agora não tem nada a ver com a anterior. Com essa mudança, qualquer comparação de desempenho em relação ao que se tinha antes fica prejudicada.

Fora isso, como eu sou implicante com a execução de comandos externos desnecessários e com a leitura de todos os dados para a memória de uma vez só (a não ser que haja garantias de que não se vai provocar estouro da memória), eis uma forma de fazer as transformações usando apenas recursos internos do Bash (produzindo saída como a do programa atual, não como o anterior).

# Os três redirecionamentos abaixo podem ficar fora do loop mais externo
# (o que percorre a lista de arquivos). Se assim se fizer (e assim se deveria fazer),
# os operadores de redirecionamento podem ser trocados de “>>” para “>”, e isso
# bastará para zerar seu conteúdo
exec 5>> "$criaCam1"
exec 6>> "$criaCam2"
exec 7>> "$criaCam3"

# Redireciona entrada a partir do arquivo recebido da lista de arquivos.
exec 4< "$arquivo"
first_line=0
if read -u 4 linha; then
echo -n ${linha^^} >&5 # Transforma para maiúsculas.
minusc=${linha,,} # Transforma para minúsculas.
echo -n $minusc >&6
# O bloco abaixo separa as palavras individuais e converte apenas as primeiras letras.
pmaiusc=""
while [[ "$minusc" =~ ([[:alnum:]]+[^[:alnum:]]*)(.*) ]]; do
pmaiusc+=${BASH_REMATCH[1]^}
minusc="${BASH_REMATCH[2]}"
done
echo -n $pmaiusc >&7
while read -u 4 linha; do
echo -n "" ${linha^^} >&5 # Transforma para maiúsculas.
minusc=${linha,,} # Transforma para minúsculas.
echo -n "" $minusc >&6
# O bloco abaixo separa as palavras individuais e converte apenas as primeiras letras.
pmaiusc=""
while [[ "$minusc" =~ ([[:alnum:]]+[^[:alnum:]]*)(.*) ]]; do
pmaiusc+=${BASH_REMATCH[1]^}
minusc="${BASH_REMATCH[2]}"
done
echo -n "" $pmaiusc >&7
done
fi
exec 4<&- # Fecha descritor nº 4

# Os três fechamentos de descritores abaixo podem (e deveriam) ser movidos
# para após o encerramento do loop que percorrer a lista de arquivos.
exec 7<&-
exec 6<&-
exec 5<&-




fi
rm $N
let i=i+1
done


Não entendi essa variável i. Você não a usa com propósito nenhum no seu programa.

De todo modo, se você seguiu minha sugestão de obtenção da lista de arquivos, agora tem de fechar o descritor referente ao comando externo find, usado acima.

exec 3<&- 




01 02



Patrocínio

Site hospedado pelo provedor RedeHost.
Linux banner

Destaques

Artigos

Dicas

Tópicos

Top 10 do mês

Scripts