30 de julho de 2010

TI Verde e a Educação à Distância

por Bianca Machado Branco*

Tecnologia da Informação ecologicamente correta não é uma onda passageira. A demanda por tecnologia “verde”, ou seja, tecnologia que reduza as emissões de carbono na atmosfera e permita o consumo de energia eficiente, já é uma realidade.

Em 2009 surgiram as primeiras certificações de Gestores de TI com especialização em projetos verdes como a GIM – Green IT Management - ao passo que grandes players adotaram o SAAS (Software como Serviço) como uma estratégia verde. Baseada na tecnologia SOA (Arquitetura Orientada a Serviços), essa modalidade de venda de software reduz os custos fixos para os clientes, na medida em que elimina as licenças de uso e introduz o pagamento de uma taxa que varia conforme a utilização.

As companhias desenvolvedoras de software estão se adaptando às novas exigências do mercado, partindo de atitudes simples como: realização de vídeo conferências a fim de reduzir o uso de meios de transportes poluentes (minimizando o deslocamento de pessoal); desenvolvimento de softwares que exijam menos capacidade do hardware, ou seja, gastem menos energia por demandarem menos tempo de operação e, ainda sejam capazes de configurar impressoras que imprimam folhas em frente e verso, economizando papel.

Outra medida verde que vem tomando corpo e crescendo é o emprego da educação à distância (EAD) para treinamento de funcionários e clientes, permitindo a atualização constante de ambos e uma melhor gestão do tempo de cada um. Para se ter ideia, as possibilidades da EAD nesse sentido vão muito além das usuais. Em uma consultoria de implantação de sistema de gestão, por exemplo, com o uso de EAD, esta atividade pode ser realizada sem a presença física do consultor, o que agiliza as implementações do software e permite a rápida intervenção da empresa desenvolvedora em qualquer eventualidade. Flexibilidade e redução de custos são palavras-chave na modalidade EAD.

Em termos de qualificação de colaboradores, a EAD é uma ferramenta extremamente útil. O segmento de TI sofre com a carência de profissionais e, para suprir a demanda por mão-de-obra qualificada as desenvolvedoras estão criando pólos de tecnologia próximos aos centros de excelência em ensino, muitas vezes distantes de suas matrizes. Nesses casos, a EAD é fundamental para viabilizar o treinamento destes funcionários, sem comprometer as operações atuais.

A EAD também é uma excelente alternativa para estreitar o relacionamento com os clientes, principalmente porque existe uma tendência de migração de empresas da região Sudeste para o Norte, Nordeste ou interior por conta dos incentivos propostos pelo PAC (Programa de Aceleração do Crescimento). A pulverização de clientes atuais e potenciais para regiões mais distantes pode gerar custos de deslocamentos de pessoal e perda de agilidade no atendimento, o que afeta a logística de distribuição dos fornecedores de software e onera a prestação de serviços. Essa situação, entretanto, não representa ameaça para as empresas desenvolvedoras que já empregam a EAD como estratégia de atendimento.

Sendo assim, para pensarmos no desenvolvimento sustentável de uma companhia, é preciso que novas formas de fazer negócio, soluções, treinamentos e relacionamento com os clientes sejam colocados em pauta. Os benefícios que a TI verde e o uso de EAD oferecem às companhias são objetivos e precisos.

Por isso, é fato que em breve, todas as empresas que não aderirem à redução de poluentes e de consumo energético terão que responder aos seus acionistas, parceiros e reguladores, assim como aos clientes e à opinião pública. Porém, com a adoção de algumas das medidas citadas é possível a essas mesmas empresas reduzirem seus custos operacionais,e ainda valorizarem a sua própria imagem no mercado.

*Bianca Machado Branco possui MBA em Gestão Empresarial e formação em Análise de Sistemas. Trabalha com tecnologia da informação desde 1998. Atualmente é coordenadora de projetos na ABC71.

28 de julho de 2010

Integrando programas Delphi com o Excel - parte II

No post anterior, mostrei os passos iniciais e os conceitos básicos para se fazer uma aplicação Delphi que seja capaz de ler ou gravar informações em uma planilha Excel. Neste post eu avanço um pouco, mostrando como acessar as propriedades de uma célula ou grupo de células, seus valores, formatações e fórmulas.

Conforme escrevi em "Classes para automatização do Excel", o acesso a todas essas informações se dá através de objetos do tipo Range do Excel, não importa se você está trabalhando com uma única célula, uma linha, uma coluna ou um grupo qualquer de células dentro de uma planilha.

O exemplo abaixo mostra como preparar um Range que representa uma única célula, acessando seu valor e formatando-a como um título para o WorkSheet:
procedure TForm1.SetExcelTitle;
var ov: OleVariant;
lRange: ExcelRange;
begin
ov := _Sheet.Cells.Item[1, 1];
lRange := _Sheet.Range[ov, ov];
lRange.Font.Color := RGB(40, 40, 127);
lRange.Font.Size := 14;
lRange.Font.Bold := True;
lRange.Item[1, 1] := 'Conhecimento de Transporte eletrônico';
{ ... }
A variável _Sheet foi criada nos moldes descritos no post anterior. Para conseguirmos acessar um Range desse _Sheet, é preciso estipular quais são os limites que o definem, isto é, o Range deverá englobar uma área retangular da planilha, limitada por duas células: uma no canto superior esquerdo da área desejada e a outra no canto inferior direito dessa área. O acesso é conseguido através da propriedade Range da folha, à qual informamos essas duas células que definem a área.

E como obter essas duas células? A propriedade Cells da folha de trabalho é a resposta pois através dela conseguimos referências a localizações específicas dentro da planilha. No trecho de código no quadro anterior, é recuperada uma referência para a célula correspondente à linha 1, coluna 1 e esta referência é repassada ao Range para ganharmos acesso às propriedades que necessitamos. É o que acontece nas linhas seguintes do programa listado, onde uso o Range recuperado para alterar as caracteristicas da fonte (negrito, tamanho, etc.) e o texto a ser usado como título. Repare apenas que para mudar a cor foi preciso usar a função RGB ao invés de um dos TColor definidos pelo Delphi. Isso ocorre porque o formato de cores usado pelo Delphi é diferente do estabelecido para uso por objetos COM, com o Excel.

O conceito de acesso é o mesmo caso queira, por exemplo, mudar o formato de apresentação dos dados numa linha ou coluna:
procedure TForm1.SetExcelFormat;
var ov, ov2: OleVariant;
lRange: ExcelRange;
begin
ov := _Sheet.Cells.Item[3, 6];
ov2 := _Sheet.Cells.Item[10, 6];
lRange := _Sheet.Range[ov, ov2];
lRange.ColumnWidth := 12;
lRange.NumberFormatLocal := 'R$ #.##0,00_);[Red](R$ #.##0,00)';
lRange.HorizontalAlignment := xlRight;
{ ... }
No exemplo acima, eu recupero as localizações das células F3 e F10 (coluna 6, linhas 3 e 10) e monto com elas um Range abrangendo essas 7 células da coluna F. De posse do Range, eu modifico o comprimento da coluna para exibir 12 caracteres, instruo-o para alinhar à direita o conteúdo das células e para que esses conteúdos sejam apresentados como valores monetários (com o símbolo de Reais e duas casas decimais). Observe que para ajustar essa formatação eu usei a propriedade NumberFormatLocal de forma que eu pudesse estipular uma máscara de apresentação compatível com minha localização (ponto como separador de milhar e vírgula para separar as decimais).

Esse mesmo tipo de cuidado deve considerado quando for ajustar fórmulas em seus Ranges pois funções que podem ser usadas em fórmulas são traduzidas. Por exemplo, a função para somar o conteúdo de células tem o nome de SUM mas para o Excel em português ela pode ser inserida como SOMA. As linhas abaixo são equivalentes para quem tem o Excel em português:
lRange.Formula := '=SUM(B2:B31)';
lRange.FormulaLocal := '=SOMA(B2:B31)';
Veja outras considerações a respeito da manipulação de fórmulas neste post.

19 de julho de 2010

Integrando programas Delphi com o Excel - parte I

Já mostrei aqui no Blog quais são as principais classes disponíveis para se automatizar tarefas envolvendo o Excel, além de exemplos em VBScript de como usar essas classes para ler dados de uma planilha ou criar e formatar planilhas. Mas, como realizar essas mesmas tarefas diretamente em um programa feito em Delphi ? Esta questão é pertinente se você já tem programas Delphi pois, para o usuário, é mais prático (e elegante) manipular dados que já se tenha à mão. Caso contrário, o usuário terá que sair do programa para executar um script externo.

Também já abordei em outras ocasiões que o Delphi é capaz de gerar códigos fontes para permitir que um programa trabalhe com classes COM publicadas por qualquer aplicativo e que o Excel é um aplicativo que publica suas funções com essa tecnologia. Mas, para facilitar, o Delphi traz uma paleta de componentes chamada Servers que já traz encapsuladas as classes do Office (Word, Excel, Outlook, etc.), poupando-nos o trabalho de gerá-las manualmente.

No entanto, esses componentes foram criados de uma forma na qual não é possível determinar visualmente a relação precisa entre eles, exigindo do programador um conhecimento prévio dessas relações para fazê-las funcionar corretamente. No caso do Excel, o ponto de entrada para a integração é a classe Application, representada pelo componente TExcelApplication. Outros dois componentes importantes são TExcelWorkbook (uma planilha) e TExcelWorksheet (uma folha ou tabela dentro da planilha). Portanto, construir um programa Delphi que crie uma planilha exigirá que incluamos os três em um Form:
TForm1 = class(TForm)
_AppExcel: TExcelApplication;
_Book: TExcelWorkbook;
_Sheet: TExcelWorksheet;
{ ... }
Os 3 componentes possuem poucas propriedades publicadas: AutoConnect indica se a conexão com o servidor COM (neste caso, o Excel) será ou não feita automaticamente – o padrão é que o programa estabeleça a conexão somente quando for precisar do servidor, ficando mais fácil de tratar eventuais erros de conexão, principalmente se o servidor não existir (Excel não está instalado).
ConnectKind estabelece como será feita a conexão do componente com o Excel (servidor COM), sendo padrão o valor ckRunningOrNew. Com esse valor, a conexão é feita com um Excel que já esteja em execução. Se não houver nenhum, o programa o executa automaticamente antes de se conectar. Para esse exemplo, vou manter as propriedades desses componentes com seus valores padrões.

O segredo para utilizar esses componentes é conectá-los corretamente entre si, preparando o ambiente em que eles atuarão. Basicamente, o código para preparar o ambiente é o seguinte:
procedure TForm1.InitExcel;
var lExcelWorkBook : _WorkBook;
lSheetInterface : IDispatch;
begin
try
_AppExcel.Connect;
_AppExcel.DisplayAlerts[[0] := false;

lExcelWorkBook := _AppExcel.Workbooks.Add(xlWBATWorksheet, 0);
_Book.ConnectTo(lExcelWorkBook);

lSheetInterface := _Book.Worksheets.Item[1];
_Sheet.ConnectTo(lSheetInterface As _Worksheet);
_Sheet.Name := 'Minha Planilha';
except
on Exc: Exception do
_Erro := 'Não foi possível iniciar o Excel.'#13''#10'' + Exc.Message;
end;
end;
O que acontece no código acima é o seguinte :
Como o ponto de partida para a integração é o componente TExcelApplication, primeiro conecto-o ao servidor COM, isto é, ao próprio Excel. O componente "sabe" quem é o servidor correto porque essa informação está embutida nele, bastando que se chame o método Connect.
Por achar mais apropriado, configuro a propriedade DisplayAlerts para evitar que o Excel mostre suas caixas de diálogo pedindo confirmações ao usuário do meu programa.
Uso a propriedade Workbooks para criar uma nova planilha vazia, o que é feito através do método Add. O valor retornado pelo Add representa a planilha (Workbook) que foi adicionada.
O valor representando a nova planilha é recuperado num variável e, em seguida, usado para conectar ao componente TExcelWorkbook que agora representa exatamente a mesma planilha, podendo ser usado para manipulá-la ao longo do programa.
Um Workbook é composto de uma ou mais folhas de trabalho, que é quem mantem as células, seus valores, fórmulas, formatações, etc. Por isso, o passo seguinte é recuperar a primeira dessas folhas e conectá-la ao componente TExcelWorksheet, disponibilizando as informações contidas.
A última operação renomeia a folha de trabalho, ajustando-lhe o título para 'Minha Planilha'.

Essa é a "receita de bolo" ! Agora, basta utilizar esses 3 componentes para alimentar os dados numa planilha, formatá-la, etc. Quando tiver terminado as operações com a planilha e com o Excel, é importante fazer a desconexão e encerrar a aplicação para devolver ao Windows os recursos utilizados:
var vip: Variant;
begin
_Book.SaveAs ('Planilha.xls', xlExcel7, vip, vip, false, false, xlNoChange, false, false, vip, vip, vip, 0);
_Sheet.Disconnect ();
_Book.Disconnect ();
_AppExcel.Quit ();
_AppExcel.Disconnect ();
A primeira parte do código anterior salva a nova planilha com o nome de Planilha.xls. Repare ainda o uso da variável chamada vip, do tipo Variant : ela não é iniciada com valor algum. Desse modo, os parâmetros não-obrigatórios da função SaveAs são forçados a assumir seus valores padrões, livrando-nos de ter que providenciá-los.

Volto em outro post para mostrar como trabalhar com uma célula específica ou uma faixa de células, seus valores, formatações e fórmulas de dentro de um programa Delphi.

16 de julho de 2010

Estados Unidos propõe identificação única na internet

No final de junho de 2010, o governo americano divulgou o rascunho de um documento onde propõe a criação de um mecanismo que permitirá aos usuários se identificarem uma única vez para realizar qualquer operação na internet.

A ideia básica da proposta é envolver o governo e empresas privadas para implementar um ambiente confiável, onde cada parte envolvida em uma transação qualquer na internet (pessoas, empresas, equipamentos) teria uma identificação única atribuída por uma autoridade certificadora reconhecida. Desse modo, todos teriam certeza sobre a identidade dos demais envolvidos em cada transação, dificultando a ocorrência de ciberataques, roubos de identidades, violações de propriedade intelectual e toda sorte de fraudes online.

O rascunho foi colocado em consulta pública para ser aprimorado e desde então vem sendo analisado por especialistas e interessados em geral. Com isso, começaram a surgir as primeiras críticas, conforme mostra a reportagem reproduzida abaixo que foi publicada originalmente no site IDG Now :

Os esforços do governo norte-americano para identificar cibercriminosos podem violar princípios de privacidade e anonimato, e nem por isso tornarão a identificação da origem dos ataques mais eficaz, disseram especialistas de privacidade e cybersegurança.

Para Robert Knake, do Conselho para Relações Externas, novas tecnologias de identificação poderiam ser usadas por governos opressivos para monitorar inimigos políticos.

Propostas para rotular pacotes de dados IP com identificadores únicos seriam mais úteis para regimes autoritários monitorarem e controlarem o uso da Internet pelos cidadãos do que para combater cibercrimes, ciberguerras e comportamentos inapropriados", disse Knake.

Em ataques maciços, a identificação do responsável não é complicada, porque poucas nações tem capacidade de realizar algo nesse volume. Mas ataques simples não provocam alertas nacionais, ele disse. "Em vários casos, o que nos falta é capacidade de resposta", afirmou. "Nós não sabemos o que fazer quando descobrimos que os chineses invadiram servidores da Google", disse Knake.

Knake sugeriu que o governo norte-americano se concentre mais em prevenção de danos e em proteger seus sistemas do que em procurar culpados.

Para Ed Giorgio, presidente da fabricante de cibersegurança Ponte Technologies, responsável por novos protocolos que identificariam usuários em redes sensíveis, existem maneiras para trabalhar a identificação do usuário.

"Em zonas menos sensíveis de Internet, por exemplo, as pessoas devem ter tokens (dispositivos de segurança), emitidos por uma empresa confiável, que estabelecem a sua identidade", disse Giorgio.

Mas propostas para criar um "Internet ID" podem até não ter legalidade nos EUA, disse Marc Rotenberg, presidente do Centro de Informação para Privacidade Eletrônica (EPIC). O país tem uma longa tradição de permitir a livre expressão anônima ou sob pseudônimo, e a justiça do país têm garantido esse direito, disse.

"Não importa a tecnologia usada – provavelmente ela não conseguirá identificar todos os atacantes mais sofisticados, porque muitas vezes eles passam por servidores em diversos países, e isso exigiria uma política coordenada em escala global quase impossível de ser alcançada", afirmou Rotenberg.

Como o documento ainda é um rascunho e está na fase de consulta pública, o governo americano está aceitando sugestões para melhorar a proposta.

10 de julho de 2010

Controlando Serviços do Windows através de APIs

Há situações em que um programa precisa obter informações a respeito de Serviços do Windows para saber seus estado atual ou até mesmo para instalar automaticamente um serviço que seja necessário.

Um exemplo é o programa que configura o Agendador da ABC71 - programa que executa processos e relatórios do nosso ERP previamente agendados. Uma das funções inerentes ao Configurador é exibir o status atual do Serviço de Agendamento, dando ao usuário rapidamente a informação se o Servfiço está instalado, se está em execução, etc.

O Windows fornece um conjunto de funções (APIs) para este tipo de operação. A base do acesso aos Serviços do Windows é o Service Control Manager (SCM), uma espécie de repositório que armazena as informações sobre os serviços. Como todo objeto do Windows, acessar o SCM exige a obtenção de um handle, que deve ser desalocado quando não for mais ser usado. Abra a conexão com o SCM usando a função OpenSCManager e notifique o fim do uso com CloseServiceHandle.
SC_HANDLE scmHnd = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);

if (scmHnd != NULL)
{
/* ... */
CloseServiceHandle (scmHnd);
}
O último parâmetro de OpenSCManager estabelece o tipo de permissão de acesso será atribuída ao handle retornado e indicando o tipo de operação que poderá ser executada com esse handle. No código acima, usei o valor predefinido SC_MANAGER_ALL_ACCESS, que significa que o handle poderá ser usado em qualquer das funções da API de Serviços. No entanto, apenas processos com privilégios de administrador poderão obter um handle que permita instalar um novo serviço. Veja Access Rights for the Service Control Manager para mais informações.

Com handle para o SCM, podemos pesquisar o estado de um serviço e exibir este estado para o usuário. Para realizar uma operação num serviço que já existe, devemos antes abrí-lo como a função OpenService, que também retorna um handle. Com esse handle podemos, entre outras coisas, iniciar e interromper a execução do Serviço associado ou obter o estado atual dele:
SC_HANDLE sh = OpenService(scmHnd, "SchedService", SC_MANAGER_ALL_ACCESS);
AnsiString Status = "Status Desconhecido";

if (sh != NULL)
{
SERVICE_STATUS lpInfo;

if (QueryServiceStatus(sh, &lpInfo) )
{
switch (lpInfo.dwCurrentState)
{
case SERVICE_RUNNING :
Status = "está em execução";
break;
case SERVICE_STOPPED:
Status = "está interrompido";
break;
case SERVICE_CONTINUE_PENDING :
case SERVICE_START_PENDING :
Status = "está sendo iniciado";
break;
case SERVICE_PAUSE_PENDING :
case SERVICE_STOP_PENDING :
Status = "está sendo interrompido";
break;
case SERVICE_PAUSED :
Status = "está pausado";
break;
}
}
CloseServiceHandle (sh);
O nome do Serviço passado como parâmetro para o OpenService é o mesmo encontrado no console de Serviços existente nas Ferramentas Administrativas do Windows - acesse as propriedades do Serviço e veja o valor de Service Name.

A função QueryServiceStatus retorna uma estrutura do tipo SERVICE_STATUS preenchida com uma série de dados sobre Serviço, incluindo seu estado.

Há ainda funções para instalar e desinstalar um serviço, equivalentes a executar um serviço criado com Delphi ou C++ Builder com os parâmetros /INSTALL ou /UNINSTALL. Essas funções são CreateService para instalar um novo serviço (cujos parâmetros permitem estipular um nome interno e outro de exibição para o serviço, o tipo de inicialização desejado, credenciais para login no Windows, caminho do programa que executa o serviço, etc.) e DeleteService para remover do SCM um serviço.

8 de julho de 2010

Funcionamento de Serviços FTP

por Ricardo Matuda*

O FTP é um dos meios mais comuns de se copiar arquivos de um lugar para outro na Internet. É bastante antigo, sendo suportado até por sistemas Mainframe. Sendo tão antigo, é um protocolo muito simples e não foi projetado para atender os requisitos de segurança que se fazem necessários nos dias atuais. Por isso mesmo, precisamos entender o seu funcionamento (pelo menos o básico) para podermos ajustar o ambiente de rede, configurando a disponibilidade e a segurança do processo.

A porta 21 é utilizada para estabelecer e manter a comunicação entre o cliente e o servidor. Essa sessão também é conhecida como Control Channel. É ela quem verifica se a conexão com o servidor ainda existe.

A porta 20 é utilizada para a transferência dos dados (arquivos), propriamente dita. É conhecida também como Data Channel. É nela que é feito o controle do fluxo e integridade dos dados.

Para utilizar o FTP, a estação cliente realiza uma conexão com o servidor FTP na porta 21. Após a conexão estabelecida, para cada arquivo transferido estabelece-se uma nova conexão, chamada de conexão de dados. Por padrão, a porta TCP 21 é usada no servidor para controlar a conexão, mas a conexão de dados é determinada pelo método que o cliente opta quando se conecta ao servidor. Existem 2 métodos para a conexão:

Conexões FTP de modo ativo são algumas vezes chamadas de conexões "gerenciadas pelo cliente" porque o cliente envia um comando PORT ao servidor, usando a conexão do controle. O comando solicita ao servidor que estabeleça uma conexão de dados da porta TCP 20 no servidor até o cliente com a porta TCP especificada pelo comando PORT.
FTP Ativo

Conexões FTP de modo passivo são às vezes chamadas de conexões "gerenciadas pelo servidor" porque, depois que o cliente emite o comando PASV, o servidor responde com uma de suas portas temporárias usadas como a porta do servidor na conexão de dados. Depois que um comando de conexão de dados é emitido pelo cliente, o servidor se conecta ao cliente usando a porta imediatamente acima da porta do cliente na conexão do controle.
FTP Ativo

O problema que ocorre com mais freqüência no FTP pela Internet envolve a transferência de dados por servidor proxy, firewall ou dispositivo de conversão de endereços de rede (NAT). Em muitos casos, esses dispositivos de segurança de rede permitem que a conexão de controle seja estabelecida na porta TCP 21 (ou seja, o usuário faz o logon com êxito no servidor FTP); porém, quando o usuário tenta realizar uma transferência de dados do tipo DIR, LS, GET ou PUT, o cliente FTP aparentemente para de responder porque o dispositivo de segurança da rede bloqueia a porta de conexão de dados especificada pelo cliente. Se o dispositivo de segurança da rede der suporte a logs, você poderá verificar o bloqueio da porta consultando os logs de negação/rejeição do dispositivo de segurança.

O firewall com filtro de pacotes com base no estado da conexão consegue analisar todo o tráfego da conexão FTP, identificando qual o tipo de transferência que será utilizada (ativa ou passiva) e quais as portas que serão utilizadas para estabelecer a conexão. Sendo assim, todas as vezes que o firewall identifica que uma transferência de arquivos se realizará, é acrescentada uma entrada na tabela de estados, permitindo que a conexão seja estabelecida. As informações ficam armazenadas na tabela somente enquanto a transferência do arquivo é realizada.

Com FTP ativo, quando um usuário se conecta ao servidor FTP remoto e solicita informações ou um arquivo, o servidor FTP abre uma nova conexão com o cliente para transferir os dados. Esta é a chamada conexão de dados. Para iniciar, o cliente FTP escolhe uma porta aleatória para receber a conexão de dados, envia o número da porta escolhida para o servidor FTP e fica esperando uma conexão nessa porta. Então o servidor FTP inicia a conexão com o endereço do cliente na porta escolhida e transfere os dados. Isto se torna um problema para usuários atrás de um gateway NAT tentando se conectar a servidores FTP.

Por causa da forma como NAT funciona, o servidor FTP inicializa a conexão de dados se conectando ao endereço externo do gateway NAT na porta escolhida. A máquina fazendo NAT receberá o pedido, mas como não possui mapeamento para o pacote na tabela de estado, descartará o pacote sem entrega-lo ao cliente.

No modo FTP passivo, o cliente pede ao servidor que escolha uma porta aleatória para ouvir esperando a conexão de dados. O servidor informa ao cliente a porta escolhida e o cliente se conecta na porta para transferir os dados. Infelizmente, isto nem sempre é possível ou desejável, por causa da possibilidade do firewall em frente ao servidor FTP bloquear a conexão de dados em portas aleatórias.

*Ricardo Matuda é formado em Análise de Sistemas. Atualmente é DBA na ABC71 e um entusiasta da tecnologia de informações.

Mais Informações
File Transfer Protocol