Clipper On Line • Ver Tópico - Práticas que facilitam programar Clipper/Harbour

Práticas que facilitam programar Clipper/Harbour

Aqui você poderá oferecer suas Contribuições, Dicas e Tutoriais (Texto ou Vídeo) que sejam de interesse de todos.

Moderador: Moderadores

 

Práticas que facilitam programar Clipper/Harbour

Mensagempor JoséQuintas » 06 Nov 2015 13:55

Complementando esse último trecho do post anterior:

Porque #define, não dá no mesmo?

SEEK "PISCCC" + codigo

SEEK AUX_PISCCC + codigo


Considerando o #include e a compilação -w3 -es2

No primeiro caso, só vamos saber do erro quando o cliente avisar que deu errado.

No segundo caso, o compilador já rejeita o fonte, porque já enxergou que está errado.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18009
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor Nascimento » 08 Nov 2015 00:05

muito boas essas aulas amigo parabens vai abrindo nossa visão sobre como melhorar nossas tecnicas de programaçao
A arte de programar é simplesmente fazer seus pensamentos serem interpretados por uma maquina :) clipper 5.3 /harbour/minigui
Avatar de usuário

Nascimento
Usuário Nível 4

Usuário Nível 4
 
Mensagens: 711
Data de registro: 19 Jul 2008 12:11
Cidade/Estado: OLINDA-PE
Curtiu: 110 vezes
Mens.Curtidas: 76 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor JoséQuintas » 20 Nov 2015 21:08

No meu aplicativo tenho lá a estrutura do DBF.
Ao carregar o sistema, ele verifica se a estrutura está ok.
Então, agora acrescente o campo do CEST nos produtos:
      { "IECEST",    "C", 8 }, ;


Pronto, quando o cliente atualizar versão, vai ser criado o campo no arquivo DBF.

E não é só isso, no programa principal tenho lá a versão dos DBFs:

   AppVersaoDbf( 20151105 )


Quando o cliente atualizar versão, se esse número for diferente do que ele usa, ao executar pela primeira vez, isso faz com que o aplicativo saiba que haverá mudança de estrutura.

Então o aplicativo primeiro "expulsa" os usuários do aplicativo, pra poder fazer o backup e depois atualizar estrutura.
Enquanto não conseguir fazer isso, ninguém mais usa o aplicativo.

Então faz backup, atualiza estrutura (já eliminando índices do arquivo modificado), e já cria os índices para garantir que se existem novos índices em novos campos, já sejam criados.

No MySQL já comecei a criar esse tipo de coisa, mas não tão flexível quanto as rotinas pra DBF.

Isso facilita muito.
Nada de mexer ou ajustar DBF em cliente manualmente.
É atualizar versão e tudo é ajustado automaticamente.

Comecei com isso quando tinha vários aplicativos diferentes, cada cliente com o seu.
Cada cliente com estrutura de arquivo diferente, telas de cadastro diferentes, etc.
Agrupei todos os EXEs em um, agrupei definições de estrutura, coloquei essa atualização automática.
Com o tempo, fui padronizando todos.
Deixava para o aplicativo modificar estruturas, fazer conversões aonde necessário, etc.
Até mesmo se precisar liberar uma opção pra determinado usuário, de determinada empresa, consigo acrescentar para o aplicativo fazer automático.

Isso resume tudo a falar para o cliente: atualize o aplicativo e já fica resolvido.

Lógico, já aconteceram imprevistos no passado.
Quando isso ocorreu, bastou utilizar o backup que o sistema havia feito.
E já alterar nos fontes para que não acontecesse novamente.

Lembro de uma única vez onde a estrutura no EXE foi problema:
Era um 486 SX, com problemas de mau contato, e o EXE se alterava ao ser carregado, considerando estruturas diferentes, e convertia sem precisar, modificando estruturas.
Esse tipo de coisa não se esquece...
Chamou a atenção o monitor piscando, então parecia normal, um monitor com problema.
Na prática era a placa mãe do computador com problema que fazia o monitor piscar.
Já não lembro em que ano foi, mas 486 SX é de muito tempo atrás.

Nesse caso, foi só retornar o backup que o aplicativo fez antes de atualizar.

De lá pra cá, já não lembro mais quando precisei de um backup.
Mas isso continua sendo feito.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18009
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor asimoes » 21 Nov 2015 10:25

Excelentes informações Quintas,

Com a relação ao dbf, o único problema de acrecentar um campo novo em um dbf, que provavelmente será populado a partir da atualização do sistema, é o passado, registros com conteúdo vazio, seria muito interessante se houvesse um campo tipo varchar no dbf.
â–ºHarbour 3.x | Minigui xx-x | HwGuiâ—„
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar de usuário

asimoes
Colaborador

Colaborador
 
Mensagens: 4919
Data de registro: 26 Abr 2007 16:48
Cidade/Estado: RIO DE JANEIRO-RJ
Curtiu: 341 vezes
Mens.Curtidas: 258 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor JoséQuintas » 21 Nov 2015 16:40

O mais parecido a varchar seria o campo memo, mas ocupando no mínimo 10 caracteres.
Na SIXCDX havia alguns recursos a mais aproveitando o campo memo.

Mas registro de tamanho variável tem seus prós e contras.
Lembro de ter lido que mesmo no MySQL, registros de tamanho fixo deixam as coisas mais rápidas.
Só imaginar que sendo fixo, a posição do milésimo registro seria algo como tamanho * 1000, o que agiliza posicionamentos.

Ainda sobre o campo novo, em alguns casos a conversão grava valor no campo novo.
Tem casos aonde é possível fazer isso, e tem casos aonde é necessário um conteúdo pra que novas rotinas/relatórios funcionem.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18009
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor JoséQuintas » 28 Nov 2015 10:08

Tenho no aplicativo uma variável pública que guarda o nome do módulo em uso: m_Prog
Deixo os relatórios com muitas opções disponíveis, pra alterar o comportamento dos relatórios.
Aconteceu agora de precisar limitar opções no relatório, porque tem opções que só interessam ao gerente.

O nome do módulo é PNOT0100.
Pra facilitar esse controle, acabei criando um módulo novo.

PROCEDURE PNOT0101
   DO PNOT0100
   RETURN


Sim, só isso mesmo no módulo novo.

Já no PNOT0100, acrescentei algumas coisas simples:

   acTxtOpcoes := { "Sem Rentabilidade" }
   IF m_Prog == "PNOT0100"
      AAdd( acTxtOpcoes, "Com Rentabilidade" )
   ENDIF


Resultado:
Se chamar o módulo PNOT0100, o usuário pode escolher se imprime o cálculo de rentabilidade
Se chamar o módulo PNOT0101, não há opção de escolha.

Como todo controle de módulos é por senha, então é liberar PNOT0101 para o usuário comum, e PNOT0100 para o gerente.

Melhor do que criar outro programa com opções diferentes, e aumentar o trabalho na hora de fazer ajustes..

m_Prog é uma variável pública, preenchida pelo programa de menu, ao escolher uma opção.
Continuo usando em multithread, sem problemas.

Solução simples, apenas fiz uso de uma variável do aplicativo, sem precisar nada avançado ou complicado.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18009
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor JoséQuintas » 28 Nov 2015 10:53

Uma tela com configuração ilimitada de parâmetros, por exemplo uma digitação no caixa.
Parece algo complicado, não?
Vamos a um cadastro simples, chama-lo de TIPOLANC:

CODIGO, N, 1
DESCRICAO, C, 30
PARAMETROS,C,100


A tela de digitação de lançamentos do caixa, simples também:

Tipo de lançamento....:
Histórico....:
Valor...:


Vamos supor que dependendo do tipo de lançamento, queira informações diferentes.
Pode querer código de cliente, número de docto, número de banco, etc.
Quer que fique tudo automático, configurável.

Agora que tal este fonte:

@ 1, 0 SAY "Tipo de lançamento...:" GET nTipoLancto VALID ValidaTipoLancto( nTipoLancto )
READ
SELECT TIPOLANC
SEEK nTipoLancto
@ 2, 0 SAY "Histórico.....:" GET cHistorico PICTURE "@!"
IF "DIGITACLIENTE" $ tipolanc->Parametro
   @ Row() + 1, 0 SAY "cliente..:" GET nCliente PICTURE "999999" VALID ValidaCliente( @nCliente )
ENDIF
IF "DIGITADOCTO" $ tipolanc->Parametro
   @ Row() + 1, 0 SAY "Documento..:" GET nDocto PICTURE "999999" VALID ValidaDocto( @nDocto )
ENDIF
IF "DIGITABANCO" $ tipolanc->Parametro
   @ Row() + 1, 0 SAY "banco...:" GET nBanco PICTURE "999999" VALID ValidaBanco( @nBanco )
ENDIF
@ Row() + 1, 0 SAY "Valor...:" GET nValor PICTURE "999999.99"
READ

cDescricao := Trim( cDescricao )
IF nBanco != 0
   SELECT banco
  SEEK nBanco
   cDescricao := " no banco " + banco->Nome
ENDIF
IF nCliente != 0
   SELECT cliente
   SEEK nCliente
   cDescricao += " do cliente " + cliente->Nome
ENDIF
IF nDocto != 0
   cDescricao += " docto " + Str( nDocto )
ENDIF


Pronto.
Agora só cadastrar lá no TIPOLANC, por exemplo:
1, Depósito no Banco, "DIGITABANCO"
2, Recebido de cliente, "DIGITACLIENTE"
3, Emissão de cheque, "DIGITABANCO,DIGITADOCTO"

Para cada tipo de lançamento, um comportamento diferente.

Agora só expandir isso pra pedidos, nota fiscal, impostos, etc. e teremos tudo se auto-configurando.
Recursos avançados? Sim, o CÉREBRO, atende todas as rotinas.
E o limite é a imaginação.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18009
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor JoséQuintas » 29 Nov 2015 14:36

Certas coisas são pessoais, aqui um exemplo pessoal que usei.
Crio uma lista de códigos pra pesquisar no MySQL:

Desta forma ficaria errado:
"... WHERE OR CODI=1 OR CODI=2 OR CODI=3"

cSql := "... WHERE "
FOR nCont = 1 TO 3
   cSql += " OR CODI=" + Str( nCont )
NEXCT


Desta forma fica correto, não colocando OR no primeiro, mas achei que visualmente o fonte não ficou bom.
"... WHERE CODI=1 OR CODI=2 OR CODI=3"

cSql := "... WHERE "
FOR nCont = 1 TO 3
   cSql += iif( nCont == 1, "", " OR" ) + " CODI=" + Str( nCont )
NEXT


Acabei preferindo assim:
cSql := "... WHERE 1=2"
FOR nCont = 1 TO 3
   cSql += " OR CODI=" + Str( nCont )
NEXT


Acaba sendo o mesmo resultado, já que 1=2 não seleciona nada.
"... WHERE 1=2 OR CODI=1 OR CODI=2 OR CODI=3"
Achei mais interessante desse jeito, pro fonte ficar mais simples.
Quem vai ter que enxergar o fonte sou eu, e não o compilador, então escolhi o que seria melhor pra mim.
Questão pessoal apenas.

Muitas vezes o comando não se limita a isso, então tem horas que convém facilitar.

Por falar nisso, uma dica interessante:
Para o SQL não importa CR+LF, ele é desprezado.
Mas se tiver que conferir alguma coisa, separar em linhas ajuda, por exemplo pra conferir na tela.

MsgBox( cSql )
"SELECT
ENDERECO
FROM IMOVEL
WHERE
( 1=2 OR CODI=1 OR CODI=2 )"


Lembrem-se sempre disso:
O fonte não se limita ao que é melhor para o compilador, ou a ganhar segundos de execução ou alguns bytes de memória.
Cada um tem que encontrar sua forma confortável de trabalhar com o fonte.
Mexer nos fontes tem que ser algo confortável, e não algo terrível.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18009
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor JoséQuintas » 29 Nov 2015 20:00

Tempos atrás peguei um aplicativo pra converter.
A primeira coisa era referente a impressão.

Num primeiro momento alterei tudo pra:

PrintBegin()
... // relatório
PrintEnd()


A situação curiosa foi esta:

Ao invés de trocentos relatórios pendentes pra resolver, fiquei apenas com 2 funções pra resolver.
Ao ajustar as funções, tudo resolvido.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18009
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor Toledo » 29 Nov 2015 20:16

O que pode ajudar é arquivo CH:

#command SET PRINTER TO                => ;
               Set_PrinterOFF()

#command SET PRINTER TO <(file)> [<add: ADDITIVE>]    => ;
               Set_PrinterON( <(file)>, <.add.> )

Assim nem precisa alterar os PRG dos relatórios.

Abraços,
Toledo - Clipper On Line
toledo@pctoledo.com.br
Harbour 3.2/MiniGui/HwGui
Faça uma doação para o fórum, clique neste link: http://www.pctoledo.com.br/doacao
Avatar de usuário

Toledo
Administrador

Administrador
 
Mensagens: 3038
Data de registro: 22 Jul 2003 18:39
Cidade/Estado: Araçatuba - SP
Curtiu: 263 vezes
Mens.Curtidas: 258 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor JoséQuintas » 29 Nov 2015 21:57

Bem pensado, mas seria no SET DEVICE TO PRINT, que é o mais comum.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18009
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor JoséQuintas » 12 Jan 2016 13:52

Usando um termo que usei num post recente:

Dividir rotinas por "assunto" / funcionalidade.

IF .NOT. AbreArquivos()
   RETURN
ENDIF
cOpcao := " "
DO WHILE .T.
   TelaCadastro()
   cOpcao := SelecionaOpcao()
   DO CASE
   CASE cOpcao == "I" // inclusão
      TelaInclusao()
   CASE cOpcao == "A" // alteração
      TelaAlteracao()
   ENDCASE
ENDDO
CLOSE DATABASES


Esse exemplo poderia ser de um cadastro, tela de pedidos, etc.
Assunto 1: abrir arquivos, está em AbrirArquivos()
Assunto 2: A tela com as informações está em TelaCadastro()
Assunto 3: A escolha de opções está em SelecionaOpcao()
Assunto 4: Inclusão em TelaInclusao()
Assunto 5: alteração em TelaAlteracao()
Assunto 6: tudo isso funcionando

A rotina que faz tudo tem o que precisa.
Ela chama a abrirarquivos() e só precisa saber se deu certo.
Ela chama a que coloca as informações na tela
E ela chama a que faz com o que o usuário escolha uma opção, só precisa saber o que foi que o usuário escolheu, não importa se é texto, gráfico, botões, setinha, etc.

Então, cada "assunto" tratado no seu lugar.

Tá muito dividido... vai ser difícil achar erro.

Ué... vamos pensar nos tipos de erro, e como localizar:

deu erro de arquivo não aberto.
Só olhar o bloco de abrir arquivo, tá lá bem identificado no fonte com o nome AbreArquivos()

deu erro que escolhe uma opção e faz outra
Conferir no fonte, se está usando a letra certa de retorno das opções.
E conferir no SelecionaOpcoes() se está selecionando certo.
Sö pode ser uma coisa ou outra.

deu erro durante a inclusão
olhar a rotina de inclusão.

Então, fonte maior ou não, tá até mais fácil chegar ao local do erro.
E está fácil alterar, porque a rotina só trata daquele "assunto".

Lógico, não vá fazer isso multiplicando variáveis públicas e private.
Procure deixar as variáveis de uma rotina dentro da rotina, LOCAL, não espalhar variáveis public/private pelas várias funções.
Cada "assunto" tem que tratar suas próprias variáveis.
Uma função recebe variáveis, e retorna variáveis. Use isto pra transferir informação entre as rotinas.
Sim, uma função normalmente só retorna uma variável, mas pode retornar array ou receber parâmetros por referência e modificá-los.
Sempre foi assim, há mais de 20 anos, nenhuma novidade.
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18009
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor JoséQuintas » 13 Jan 2016 19:23

FOR EACH

O uso do FOR EACH é legal, deixa o fonte mais limpo.
Aqui padronizei como oElement quase sempre.

Num array, a variável do FOR EACH vai conter um elemento do array.

Compare:
FOR nCont = 1 TO Len( oFrm:Visual:Botoes )
   ? oFrm:Visual:Botoes[ nCont, 1 ], oFrm:Visual:Botoes[ nCont, 2 ], oFrm:Visual:Botoes[ nCont, 3 ]
NEXT

FOR EACH oElement IN oFrm:Visual:Botoes
   ? oElement[ 1 ], oElement[ 2 ], oElement[ 3 ]
NEXT


Em algo mais conhecido, em Directory():

FOR EACH oElement IN Directory( "*.*" )
   ? oElement[ F_NAME ], ? oElement[ F_SIZE ]
NEXT


Em strings, cada variável do FOR EACH vai ser uma letra.

FOR EACH cLetra IN cTexto
      ? cLetra
NEXT


compare

FOR nCont = 1 TO Len( cTexto )
   ? Substr( cTexto, nCont, 1 )
NEXT
José M. C. Quintas
Harbour 3.2, mingw, gtwvg, multithread, dbfcdx, ADO+MySql, PNotepad
"The world is full of kings and queens, who blind our eyes and steal our dreams Its Heaven and Hell"

https://github.com/JoseQuintas/
Avatar de usuário

JoséQuintas
Membro Master

Membro Master
 
Mensagens: 18009
Data de registro: 26 Fev 2007 11:59
Cidade/Estado: São Paulo-SP
Curtiu: 15 vezes
Mens.Curtidas: 1206 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor asimoes » 14 Jan 2016 07:30

Quintas,

São recursos do harbour que facilitam a programação.
â–ºHarbour 3.x | Minigui xx-x | HwGuiâ—„
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar de usuário

asimoes
Colaborador

Colaborador
 
Mensagens: 4919
Data de registro: 26 Abr 2007 16:48
Cidade/Estado: RIO DE JANEIRO-RJ
Curtiu: 341 vezes
Mens.Curtidas: 258 vezes

Práticas que facilitam programar Clipper/Harbour

Mensagempor asimoes » 14 Jan 2016 08:06

Quintas,

Como ficaria um FOR EACH para este caso:
FOR nIdx := 1 to 25 STEP 2
    nLinha ++
    RestScreen(nIdx, 0, nIdx+1, 79, cTAbertura[nLinha])
    SysWait(.01)
NEXT
â–ºHarbour 3.x | Minigui xx-x | HwGuiâ—„
Pense nas possibilidades abstraia as dificuldades.
Não corrigir nossas falhas é o mesmo que cometer novos erros.
A imaginação é mais importante que o conhecimento. (Albert Einstein)
Avatar de usuário

asimoes
Colaborador

Colaborador
 
Mensagens: 4919
Data de registro: 26 Abr 2007 16:48
Cidade/Estado: RIO DE JANEIRO-RJ
Curtiu: 341 vezes
Mens.Curtidas: 258 vezes

Anterior Próximo



Retornar para Contribuições, Dicas e Tutoriais

Quem está online

Usuários vendo este fórum: Nenhum usuário registrado online e 17 visitantes


Ola Amigo, espero que meu site e forum tem lhe beneficiado, com exemplos e dicas de programacao.
Entao divulgue o link da Doacao abaixo para seus amigos e redes sociais ou faça uma doacao para o site forum...
MUITO OBRIGADO PELA SUA DOACAO!
Faça uma doação para o forum
cron
v
Olá visitante, seja bem-vindo ao Fórum Clipper On Line!
Efetue o seu login ou faça o seu Registro