
Micheus
Veteranos-
Total de itens
3.189 -
Registro em
-
Última visita
Tudo que Micheus postou
-
Fireboard, apenas uma dica.Quando concatenar strings deste modo (com caracteres no meio, como neste caso) você não precisa fazer uso da função CHR. Simplesmente utilize a notação de caracter (#). O sinal "+" só se faz necessário se você colocar o resto do texto em outra linha no código (a seguinte), do contrário, não é necessário. Exemplificando: messagedlg('Não há senha digitada'#13'Digite uma senha válida',mtError,[mbok],0); ou no segundo caso: messagedlg('Não há senha digitada'#13 + 'Digite uma senha válida',mtError,[mbok],0); Abraços
-
apenas uma mãozinha nesta questão.biakeffer, dê um duplo click no componente SQLConnection. Na tela que aparece, selecionado ConectinName=MySQLConnection, você verá na lista ao lado (Connection Settings) a propriedade HosteName.
-
João Paulo Taraciuk, outra sugestão é fazer uso do componente TQRExpr. Você pode utilizar o Wizard, clicando no botãozinho "..." da propriedade Expression e construir uma expressão, utilizando os botões que na tela aparecem: - Database Field (campo das tabelas que você tem acesso no relatório); - Function (funções disponíveis e que serão interpretadas e resolvidas pelo componente); - Variable (de pouca utilidade neste caso); - Outros botões de operções (+, -, *, /, ...) Observe que a cada botão acionado, pode ser aberta uma nova janela para possibilitar uma nova composição. A medida que você vai clicando OK, vai montando a expressão final. Um exemplo de valor para a propriedade baseando no seu caso: IBQuery1.NOME_RUA +IF(IBQuery1.NUM <> '', ', ' + IBQuery1.NUM,'') - inicialmente acionei o botão Database Field e selecionei o campo NOME_RUA; - adicionei o sinal "+", visto que queremos concatenar strings e eu supus que NUM é um string, caso contrário, ainda seria necessário utilizar a função STR (Other); - acionei o botão Function e selecionei Logical->IF e cliquei em Continue. Na tela que aparece, vamos compor a expressão de avaliação; -> primeiro argumento - Logical Value. Aciona o botão "..." e montamos a expressão IBQuery1.NUM <> '', utilizando os recursos já mencionados. Com esta expressão queremos dizer que ser NUM for diferente de nulo, o resultado será verdadeiro; -> segundo argumento (p/ resultado verdadeiro) - Value. Aciona o botão "..." e montamos a expressão ', ' + IBQuery1.NUM. Esta expressão é a concatenação da vírgula, que virá após o nome da rua, com o número do imóvel; -> terceiro argumento (p/ resultado falso) - Value. Aciona o botão "..." e colocamos apenas '', de modo que ser não há número, não concatenamos nada. É por aí e funciona muito bem, depois que você se entende com este tipo de expressão mais compléxa. Abraços
-
(resolvido)Lentidão ao abrir tabela c/ Fotos
pergunta respondeu ao schaukoski de Micheus em Delphi, Kylix
schaukoski, pelo tamanho da imagem, ou você está gravando BMP ou é um JPG bastante grande mesmo.Mas quanto ao tipo, você lembra deste post. Veja que se você está utilizando imagens relativamente pequenas, você poderia (deveria) utilizar um tipo BLOB menor -> MEDIUMBLOB (até 16MB). Também observe que podem ser utilizados artifícios para minimizar isto. Como o colega Jhonas mencionou, possivelmente você está "trazendo toda a tabela de uma vez" (na verdade o fetch é feito, inicialmente, no número de registros a ser mostrados nas linhas visíveis do DBGrid), mas se você estiver mostrando a imagem para cada linha seletada no DBGrid, você pode deixar o campo imagem fora do seu select, e utilizar uma outra querie para trazer apenas a imagem do item selecionado. É conveniente também lembrar, preferencialmente não deve-se utilizar instruções SQL como "SELECT * FROM ...", devendo ser inclusos no select apenas os campos a serem efetivamente utilizados. Pelo que vejo por aí, isto é algo meio relativo e pessoal.Em ambas abordagens, há prós e contras. Colocar a imagem no banco garante a integridade desta informação, mas deixá-la em um diretório já nem tanto (pode ser excluída ou renomeada e o vínculo fica inconsistente) Abraços -
Jean Carissimi, Se for questão de bug, confira a versão do seu quickreport instalada. No site do fabricante QuSoft há para download a última versão Standard: QuickReport 3.0.5 Standard for Delphi 4. Se a sua for anterior a esta, clique no link para baixá-la e veja se resolve o seu problema. (Será solicitado um e-mail para que você possa baixá-la) Nesta abordagem sugerida pelo colega Eder, há a opção de você mudar a variável de ambiente TEMP durante a execução do seu relatório (no seu programa), restaurando-a após sua conclusão. Veja dica do colega Churc neste post. Apesar de que, neste tipo de problema, normalmente é emitida uma mensagem de erro quando o quick tenta criar o arquivo temporário, o que não foi citado pelo colega Diogo Moraes. (motivo pelo qual, acredito não seja este o problema) E, além destes itens que o colega Jhonas sugere sejam observados, eu inda acrescentaria: 7 - para ter certeza de que o preview está sendo executado mesmo que não hajam dados, manter a propriedade PrintIfEmpty do QuickRep TRUE. Abraços
-
MXVinícius, lá no seu primeiro post, o principal problema deve-se ao fato de você estar convertendo para texto as datas no if. você deveria utilizar o formato datetime. Tente mudarif TPagarDataVencimento.AsDateTime < Date then e o outro if TPagarDataVencimento.AsDateTime > Date then Experimente alterar e ver como ele se comporta. Não avaliei sua lógica, mas com esta alteração você vai poder comparar corretamente as datas. Abraços
-
(Resolvido) Como Salvar um campo atribuindo um caption nele e o v
pergunta respondeu ao robinhocne de Micheus em Delphi, Kylix
Robinhocne, desculpe a demora em responder, estive viajando em férias :rolleyes: por toda esta parte que você postou aqui, vejo que você não levou em conta o que eu havia mencionado no post#18 <_< Vou por uma a parte relevante aque, denovo: Ou seja, você não está utilizando a função que sugeri (Format), a qual gera como resultado um texto numérico onde há apenas o ponto de decimal no número (nada de vírgula, que possa atrapalhar o entendimento banco sobre o número passado). Experimente a alteração que sugeri. Antes disto, não tenho sugestões. Abraços -
(Resolvido) Imprimir Etiquetas no QuickReport
pergunta respondeu ao Recife de Micheus em Delphi, Kylix
Que bom. Caso haja necessidade, você pode adaptar este relatório para poder informar a partir de qual etiqueta começar a impressão - definir linha x coluna. Isto é interessante quando suas etiquetas não preenchem toda a folha e você pode, então, começar a impressão a partir da próxima etiqueta disponível no papel (folha ou formulário). Nesta situação, você armazena em uma variável (digamos, QtdPular), private ao form, o resultado da operação Linha*Coluna = etiquetas a pular. Então, utilizando outra variável (também private ao form, suponha QtdPulada), você inicializa ela com 0 no evento BeforePrint do QuickRep e no evento BeforePrint da banda detalhe você controla quando inicializar os labels, verificando (em portugol): ... se QtdPulada > QtdPular então início_então inicializa labels com valores do dataset fim_então senão início_senão Inc(QtdPulada) inicializa labels com branco fim_senão Algo mais ou menos assim. Abraços -
Eder, o erro foi meu. :ph34r: Basta não utilizar o parênteses, porque FIRST não é uma função. Ficaria apenas: SELECT FIRST PAGADOR_NOME Teste, deve funcionar. Abraços
-
Sim. Na verdade um QRDBText para não ter que mover o valor para o label. você monta ele junto com o outro (se em run-time) ou direto no componente (se em design-time)Seu SELECT de totalização ficou assim, não foi: SELECT PAG_CNPJ, '+ 'SUM(VALOR_FRETE) AS VALOR_FRETE_TOTAL, '+ 'SUM(CONTADOR) AS CONTADOR_TOTAL, '+ 'SUM(KG_CALCULO) AS KG_CALCULO_TOTAL, '+ 'SUM(VALOR_N_FISCAL) AS VALOR_N_FISCAL_TOTAL '+ 'FROM CTRC ' + 'WHERE (SITUACAO_CTRC <> "C") '+ 'AND DATA_EMISSAO between :datai and :dataf '+ 'AND NOME_VENDEDOR = ' + QuotedStr(COMBOBOX1.text) + 'GROUP BY PAG_CNPJ ' + 'ORDER BY 2 DESC'; O outro SELECT (no segundo dataset tipo query) ficaria: - Daí, você liga a propriedade DataSource deste último query, ao datasource que você conectou a propriedade dataset a sua query principal. Isto fará com que o parâmetro PAG_CNPJ seja obtido daquele dataset onde há um campo exatamente com este nome;- Quando você abre a consulta principal, logo após você abre esta segunda consulta (lá no início mesmo, antes do preview); - Uma vez utilizado um QRDBText para mostrar o nome do cliente, basta que você referencie ele com este último dataset e o respectivo campo (PAGADOR_NOME); - não vai precisar utilizar qualquer evento para isto. bom, as instruções acima, já levam isto em conta. Abraços
-
McBlade, mas se há um único arquivo dentro deste zip, como poderia estar havendo uma segunda interação? Eu estou sem tempo para dar um help nisto, mas haveria alguma possibilidade de o arquivo zipado conter contém o path junto ao nome do arquivo sendo descompactado? Há alguma possibilidade de o arquivo de origem não ter sido gerado pela sua rotina de compactação (a qual não guarda o path, pelo que vejo)? Se você souber utilizar o depurador, você provavelmente conseguirá achar o problema. Ponha um break-point (F5) no início da interação e acompanhar o valor das variáveis via eveluate (CTRL+F7). Abraços
-
(Resolvido) Imprimir Etiquetas no QuickReport
pergunta respondeu ao Recife de Micheus em Delphi, Kylix
esta mensagem está meio estranha. Eu baixei o arquivo, descompactei em uma pasta, compilei, executei e realmente há um erro mas pela falta do arquivo Teste.MB (conteúdo de memo) - esqueci dele, desculpem-me. :ph34r: Vai denovo ele completo com um executável também. Ao ser iniciado, o programa troca a origem de dados para o local do programa, então tudo deve estar na mesma pasta. Abraços Impressao_Etiquetas.zip -
Outra opção, seria utilizar uma banda sub-detail para as tabelas 2 e 3. Observe que muito provavelmente a tabela1 contém os dados do veículo e seria Master, enquanto as demais seriam Detalhe, ou seja 1-N. você deve ligar as tabelas 2 e 3 para a tabela 1 através do campo de relacionamento (como já mencionou o Jhonas). A forma como você as ligará, depende do tipo de dataset utilizado. Se for do tipo Query, você deverá parametrizar as tabelas 1 e 2 de modo a utilizar o campo de referência com a tabela 1. Se for do tipo Table, possivelmente você poderá fazer isto utilizando a propriedade MasterSource/MasterField das tabelas 2 e 3 e referenciando a tabela1.
-
darth_ivan, dê uma olhada no help. Procure por: IDE command-line options você encontrará esta resposta lá Abraços
-
MAS agora tem um problema...HOuve um cadastro do cliente alterado no meio do ano......o cadastro no inicio do ano tava assim: AAAAAA E agora foi alterado assim(razão social): AAAAAA SA ai o relatorio começou a mostrar assim: Notem que por causa do SA ele não juntou os dados, porque esta diferente ...... Como é que eu faço pra Juntar os registros, desconsiderando o NOME DO CLIENTE(PAGADOR_NOME) SÓ fazendo o filtro pelo CNPJ DO CLIENTE(PAG_CNPJ). Mas o nome do cliente deve aparece no relatorio Eder, acho que a opção simples é:- remova o nome do cliente da sua consulta, agrupe apenas pelo CNPJ. Isto resolve o problema da duplicação; - utilize uma consulta para buscar o nome do cliente apenas, onde o parâmetro de filtro é o CNPJ que você terá da consulta inicial. A cada impressão da linha detalhe (onde estiver sendo impresso o CNPJ), você pode, então, executar a consulta através do CNPJ atualmente selecionado na consulta principal e pegar o primeiro resultado para mover para o label que mostrará o nome da empresa no relatório. Se você estivesse utilizando o QuickReport, eu lhe diria para utilizar o evento BeforePrint, mas como você está agora utilizando o FreeReport, então acho que você é capaz de achar o evento correto. Inclusive, se você parametrizar sua segunda consulta e definir o nome do parâmetro igual ao da coluna CNPJ da consulta principal, você poderá apenas ligar esta consulta a principal via propriedade DataSource. Feito isto, ao abrir sua consulta (antes de mostrar o relatório), logo a seguir você abre esta segunda consulta (automaticamente, a cada linha movida na consulta principal, a consulta secundária será refeita. Com isto, você pode ligar a coluna nome da empresa desta consulta a um componente tipo QRDBText que ela apresentará o cliente correto) A explicação pode estar um pouco complicada, mas analisando com calma, você verá que é simples de implementar. ;) Abraços
-
José, coloquei o código abaixo de forma mais organizada (para mim). Gostaria que você respondesse: - o que é LB0, LB1, LB2, LB00 ? - está correto o uso de LB00 em todos os if's ? - em que evento você está utilizando este seu código? - o código é o mesmo para os tais 3 botões que você colocou no comentário? E o código é assim mesmo, as operações para cada botão, seguem com o else? Dica: Um código mais profissional, não utiliza o teste de variáveis boolenas como você o fez: if LB0.StateOn = True ..., já que sendo a propriedade/variável booleana e a avaliação em um if também, não faz sentido perguntar o óbvio: if (True) = True then; você simplesmente pergunta if True then. Neste sentido, quando quiser verificar se não é true, basta testar utilizando o NOT: if false = false then, ficaria simplesmente: if not True then. Lembre-se que o if then é executado quando o resultado for true, do contrário ele executará o else. begin Header:= Char($AA) +Char($55); Aud:= Char($02); //audio Vid:= Char($01); //video VA:= Char($03); //Video e Audio if LB0.StateOn and LBV.StateOn and LBA.StateOn and not LB00.StateOn then ComPort1.WriteStr(Header+VA+#$00#$00) else if LB0.StateOn and not LBV.StateOn and LBA.StateOn and not LB00.StateOn then ComPort1.WriteStr(Header+Aud+#$00#$00) else if LB0.StateOn and LBV.StateOn and not LBA.StateOn and not LB00.StateOn then ComPort1.WriteStr(Header+Vid+#$00#$00) //*****************segundo botão*********************************** else if LB1.StateOn and LBV.StateOn and LBA.StateOn and not LB00.StateOn then ComPort1.WriteStr(Header+VA+#$01#$00) else if LB1.StateOn and not LBV.StateOn and LBA.StateOn and not LB00.StateOn Then ComPort1.WriteStr(Header+Aud+#$01#$00) else if LB1.StateOn and LBV.StateOn and not LBA.StateOn and LB00.StateOn Then ComPort1.WriteStr(Header+Vid+#$01#$00) //*****************************3ºbotão********************** else if LB2.StateOn and LBV.StateOn and LBA.StateOn and not LB00.StateOn then ComPort1.WriteStr(Header+VA+#$02#$00) else if LB2.StateOn and not LBV.StateOn and LBA.StateOn and not LB00.StateOn Then ComPort1.WriteStr (Header+Aud+#$02#$00) else if LB2.StateOn and LBV.StateOn and not LBA.StateOn and not LB00.StateOn Then ComPort1.WriteStr(Header+Vid+#$02#$00); end; Aguardo suas respostas. Verei minha caixa de mensagem amanhã apenas. Quinta a noite estarei viajando em férias e só retorno a acessar a net dia 17/12/2007. Abraços José, ainda me sobraram algumas dúvidas, como por ex., se realmente o penúltimo char enviado é o nº do Source. Mas o código abaixo já dá uma simplificada no que você postou. Observe que: - utilizamos apenas uma linha para envio dos dados para a COM (ela não se repete mais); - inicializamos uma variável que diz qual o botão source selecionado (LBSource); - tratamos a seleção da opção Audio/Video em um único if. procedure TForm1.Button3Click(Sender: TObject); Const Header = Char($AA) +Char($55); Aud = $02; //audio Vid = $01; //video var VA :Byte; //Video e/ou Audio LBSource :Char; begin // inicializa o botão Source pressionado // pelo seu exemplo, parece que o penúltimo caracter enviado para a // COM é o número do source - isto é real? Se for vale o que está abaixo. if LB0.StateOn then // só haverá um LBx na posição StateOn LBSource := #00; else if LB1.StateOn then LBSource := #01; else if LB2.StateOn then LBSource := #02; // manipula flag de audio/video if LBV.StateOn then VA := Vid // se ligado inicializa com Vídeo else VA := $00; if LBA.StateOn then VA := VA or Aud; // se ligado adiciona o bit ref. Audio ao valor anterior // esta situação de LB00 não ficou clara if not LB00.StateOn then ComPort1.WriteStr(Header +VA +LBSource +#00); end; crie uma function para isto: function CharsToHexa(StrSource :String) :String; var I :Byte; begin Result := ''; for I := 1 to Length(StrSource) do Result := Result +Format('$%x', [Ord(StrSource[I])]); end; e chama assim: Label1.Caption := 'String enviada: ' +CharsToHexa(Header +Command +Source +Destination); Abraços
-
procedure TFrmCheques.FormActivate(Sender: TObject); begin FrmPrincipal.DSBotoes.DataSet := DsCheques.DataSet; end; posto o código acima e seu comentário, parece-me que por algum motivo, quando você clica inicialmente no botão Insert você está colocando outro dataset em modo inserção. Explicando: pelo seu código, o dataset ref a cheques será atribuído ao FrmPrincipal.DSBotoes.DataSet apenas quando o FrmCheques processar o evento OnActivate. Também, você chama o método Append (DsBotoes.DataSet.Append) fora o if onde você testou o FrmCheques, o que quer dizer que o dataset que está ligado a FrmPrincipal.DSBotoes.DataSet não necessariamente é o esperado, caso o evento OnActivate ocorra antes deste procedimento ser executado. O motivo de entrar em modo edição, poderia ser justamente porque o form é ativado após o processamento da procedure que o colocaria em Inserção. Ocorre que ao digitar ou editar qualquer campo automaticamente o dataset entra em modo Edição. Já quando você clica pela segunda vez, você já está com o form ativo, ou seja, o evento OnActivate ocorreu e o dataset está corretamente setado, assim, funciona. Se você souber depurar o programa, poderá colocar um break-point na linha do Append (por ex.) e verificar qual o dataset que está ligado a FrmPrincipal.DSBotoes.DataSet antes de executá-lo (utilizar CTRL+F7 para inspecionar a propriedade FrmPrincipal.DSBotoes.DataSet.Name) Abraços
-
José, você quer dizer mostrar os valores em um label no formato decimal? Se for isto você pode utilizar a função format. Veja exemplo, onde passo 3 valores como argumento: Label1.Caption := Format('$%x, $%x, $%x', [20, 54, 56]); O que diz a função para formatar o número inteiro, em hexa é o %x. O $ apenas será concatenado a string de modo a mostrar o resultado da seguinte forma: $14, $36, $38 Abraços
-
se você der uma olhada no 1º link do post #3 (lá em cima), você vai encontrar uma descrição completa dos parâmetros da linha de comando. Assim, lá consta que:-B, --databases Para copiar várias bases de dados. Neste caso, não se especificam tabelas. O nome dos argumentos refere-se aos nomes das bases de dados. Incluirá-se USE db_name na saída antes de cada base de dados. logo, você deverá concatenar o nome do banco após esta "tag". No exemplo do colega Denis, ele utilizou o nome fixo (sase), você deverá substituí-lo ou concatenar um string com o nome do mesmo na posição específica. se você observar, em ExecutarBackup é feita a inicialização da string com o comando e uma chamada à CreateProcessSimple passando este valor, logo...isto significa que você deverá chamar ExecutarBackup a partir de um botão ou de qualquer lugar que você queira - isto é a seu critério. ;) Abraços
-
você pode dar uma olhada neste post
-
A princípio não há problema, desde que o tal form esteja criado (exista em memória). Assim você não vai obter um "Access violation". Abraços
-
ah!!!você poderia dar uma olhada neste outro post onde eu coloquei um exemplo que permite a troca de mensagem entre Server e Client. No link em minha assinatura, no 4Share, tem na pasta Programação (se não me engano) mais um exemplo com Socket e tem também um programa tipo Messenger (MyMessenger) que utiliza outro recurso para troca de mensagem. Veja se lhe ajudam.
-
(Resolvido) Consulta com Radiogroups
pergunta respondeu ao Walter Gazzarrini Neto de Micheus em Delphi, Kylix
Mais uma opção... Declare uma procedure no seu form e coloque este código: procedure TForm1.AtualizaConsulta; var StrFiltro1, StrFiltro2, StrFiltro3 :string; begin case RadioGroup1.ItemIndex of 0 : // Master StrFiltro1 := 'MASTER CARD'; 1 : // Visa StrFiltro1 := 'VISA'; else StrFiltro1 := ''; end; case RadioGroup2.ItemIndex of 0 : // Débito StrFiltro2 := 'DEBITO'; 1 : // Crédito StrFiltro2 := 'CREDITO'; else StrFiltro2 := ''; end; case RadioGroup3.ItemIndex of 0 : // Parcelado StrFiltro3 := 'PARCELADO'; 1 : // A vista StrFiltro3 := 'AVISTA'; else StrFiltro3 := ''; end; if StrFiltro1 <> '' then StrFiltro1 := 'UPPER(Mastervisa_venda) = '#39 +StrFiltro1+ #39; // #39 = ' if StrFiltro2 <> '' then begin StrFiltro2 := 'UPPER(Debito_Credito) = '#39 +StrFiltro2+ #39; if StrFiltro1 <> '' then // se tem filtro 1 adiciona o AND no filtro 2 StrFiltro2 := ' AND ' +StrFiltro2; end; if StrFiltro3 <> '' then begin StrFiltro3 := 'UPPER(Parcelado_AVista) = '#39 +StrFiltro3+ #39; if StrFiltro2 <> '' then // se tem filtro 2 adiciona o AND no filtro 3 StrFiltro3 := ' AND ' +StrFiltro3; end; with dm do begin ZQueryVendas.close; ZQueryVendas.sql.clear; ZQueryVendas.sql.add('select *'); ZQueryVendas.sql.add('from tb_vendas'); ZQueryVendas.sql.add('where ' +StrFiltro1 +StrFiltro2 +StrFiltro3); ZQueryVendas.open; end; end; como você não passou o nome e tipo dos campos referentes a Debito/cretido e Parcelado/avista Pronta a procedure, se for para atualizar a consulta a cada RadioGroup clicado: procedure TForm1.RadioGroup1Click(Sender: TObject); begin AtualizaConsulta; end; procedure TForm1.RadioGroup2Click(Sender: TObject); begin AtualizaConsulta; end; procedure TForm1.RadioGroup3Click(Sender: TObject); begin AtualizaConsulta; end; se for através de um botão atualizar: procedure TForm1.Button1Click(Sender: TObject); begin AtualizaConsulta; end; Abraços -
Você está falando daquele aparelhinho eletrônico BIP ou Pager?
-
(Resolvido) Imprimir Etiquetas no QuickReport
pergunta respondeu ao Recife de Micheus em Delphi, Kylix
Felipee, acho que esta não é exatamente a questão do colega Recife. A questão a que ele parece referir-se é sobre como imprimir as etiquetas, da esquerda para a direita, e de cima para baixo. Sendo que utilizando impressão em coluna, o quick realiza a impressão de cima para baixo da esquerda para a direita. Foi neste sentido que pedi confirmação. Bom, supondo que realmente seja isto, o único meio de contornar isto no Quick Report, é controlando a impressão na mão. É algo que pode ser meio chato, mas funciona muito bem. Segue anexo um exemplo que ilustra a impressão de etiquetas de tamanho pequeno e em 3 colunas. A idéia básica é: - mantemos a propriedade Page.Columns = 1 no QuickRep; - ajustamos as margens de acordo com o papel a ser utilizado; - adicionamos uma banda do tipo Detail, e ajustamos sua altura de acordo com as necessidades; - nesta banda, colocamos QRlabels (ou o que você quiser, mas que não seja data-aware, como QRDBText), posicionados em forma de coluna. Estes componentes devem ser nomeados de modo a incluir no seu nome o nº da coluna - isso traz benefícios; - a propriedade DataSet do QuickRep deve ser mantida nula. O dataset será manipulado no evento OnNeedData; - no evento BeforePrint do QuickRep posicionamos o dataset no início (First); - no evento BeforePrint da banda, inicializamos os labels (ou outros componentes) e para cada coluna, avançamos o dataset (Next); Bom, e ver o exemplo para perceber que é mais complicado explicar do que fazer. Abraços