Blog

  • Segurança e Gestão de Riscos em Tecnologia da Informação

    Certamente você já ouviu aquele velho
    ditado de que “quando a esmola é muita,
    o Santo desconfia
    ”.

    Ultimamente, tenho refletido muito sobre este velho e sábio provérbio; tamanha é a enxurrada de banners, spams, e-mails de amigos e também de pessoas que nunca ouvi falar e outros milhares de materiais promocionais que anunciam o paraíso do mundo do “é de grátis” ou o de levar vantagem em tudo. A famosa lei de Gerson. Coitado do Canhotinha de Ouro.

    São brindes disso, acessos daquilo, moedas virtuais das quais nunca ouvimos falar – existe até um tal de pataco$ –  formulários gigantescos nos quais você tem que contar praticamente a sua vida inteira. Parecem até interrogatórios da KGB. E para que tudo isto? Mouse pads cafonas, camisetas tamanho P, descansos de telas, fotos dos produtos de um fabricante qualquer e outras centenas de dezenas de quinquilharias. Tudo bem, tudo bem, existem os concursos e sorteios de automóveis, residências, casas na praia, eletro eletrônicos, dinheiro real. Ok, ok! Mas pera lá; três automóveis para serem sorteados em um universo de 20 milhões de internautas atualmente. Vai ver que eles nem tem ar condicionado.

    O internauta desavisado não percebe que está fornecendo aos ofertantes de brindes o que há de mais valioso nos dias de hoje. Ou seja, estão dando de lambuja (entregando o ouro ao bandido) seus dados cadastrais, pessoais, bancários, financeiros, salariais, quem sabe até preferências sexuais e até mesmo seus hábitos de consumo em troca de uma chance em milhões de ganhar alguma coisa. Por menor que seja esta coisa. O negócio é se dar bem!

    Caríssimos amigos, vivemos a época da Quarta Onda – A Era da Informação – Quem detiver maior quantidade de dados, souber tratá-los de forma a virarem informações refinadas e de alto nível de precisão com grande poder de fogo, certamente ganhará a guerra, oops, quer dizer o jogo.

    Imagine a seguinte situação:

    Vamos dizer que modicamente neste ano você participe de uma promoção de Internet por mês. E que tenham sido de doze diferentes empresas. Note que por no mínimo em 12 oportunidades seus dados foram enviados a gigantes do mercado mundial de bens de consumo. Em um foi informado seu salário, em outro quantas TVs você tem, se você já comprou na grande rede, qual foi a forma de pagamento, quando irá comprar novamente. O que e por que e assim por diante.

    Digamos que nestes 12 preenchimentos você e algum familiar seu estejam participando simultaneamente em quatro. E que nestes quatro, dois sejam de um mesmo grupo empresarial. Pronto basta cruzar os seus perfis de consumo e renda para que este grupo identifique todos os seus hábitos e possibilidades financeiras para começar a te empurrar e te tentar quase que diariamente aos maravilhosos produtos que ele vende e/ou fabrica. É praticamente certo de que em um dado momento você não resista mais e realize a compra de pelo menos um alfinete dele.

    Você e também os outros 20.000.000 de internautas tupiniquins. Você acaba de perder o jogo, game over, e ainda acha que fez um bom negócio. Não percebe que foi totalmente manipulado e induzido a uma compra impulsiva e compulsiva. O pior é que ainda pagou o famoso frete.

    E no dia seguinte começa tudo de novo.

    Outro meio muito interessante de coleta de hábitos dos internautas é realizado através dos famosos softwares spyware. É isso aí mesmo, spy de espião sim. Quem não gosta de baixar música de graça da Internet? Isto era e ainda é disponibilizado “de grátis” pelos softwares de primeira geração mundial de rede peer-to-peer de compartilhamento de arquivos MP3. Napster, Gnutela (que nome?!) dentre outros. Note que estes apenas compartilham músicas. Já os de segunda geração compartilham tudo o mais o que você pensar. Vídeos, sons, softwares diversos, imagens, etc. e tal. O Windows XP é campeoníssimo de downloads nos já populares KazaA, Morpheus. E-mule, etc,… E vem por aí o Vista.

    O que muita gente não sabe é que quando estes programas estão ativados e minimizados realizando uploads e downloads, tudo que você estiver fazendo on line está sendo registrado tim-tim por tim-tim. Tais registros são catalogados e indexados, por exemplo, por data e dizem respeito a sites visitados, seus próprios downloads e uploads, links que você gravou em seus favoritos, a quantidade de tempo que ficaste em todos os sites e por aí vai. Vou mais além, eles dizem que não medem isto, acreditem se quiser, seus softwares instalados, arquivos, etc, etc,…

    Após o catálogo estar preenchido com seus dados, os mesmos são enviados através da sua própria conexão aos servidores dos desenvolvedores dos spywares e desenvolvedores dos programetas de compartilhamento ponto a ponto. Os “de grátis”. Daí é questão de tempo deles serem filtrados, tratados, refinados até virarem informação da boa e serem vendidos acompanhados dos outros dados de milhões de pessoas por pequenas importâncias de milhares de dólares. E quem está comprando? Sim, os mesmos grupos que sorteiam carros, casas, videocassetes,…

  • Internet e Justiça, um novo desafio

    A polêmica em torno do bloqueio do site “YouTube”,
    motivado pela divulgação de imagens da apresentadora
    Daniella Cicarelli e de seu namorado em uma praia na Espanha,
    nos coloca diante de um velho dilema: a distância entre
    o Direito e a tecnologia da informação. Desde a
    popularização da Internet, dez anos atrás,
    os operadores do Direito carecem de subsídios técnicos
    para tratar da questão, ao mesmo tempo em que os técnicos
    não têm noções de Direito.

    Até o momento, não temos Varas nem Câmaras
    especializadas em tecnologia da informação, tampouco
    em propriedade industrial, apesar de serem áreas que requerem
    conhecimentos específicos. Os juízes e os desembargadores
    dependem de peritos para subsidiarem suas decisões, visto
    que julgam os mais diversos assuntos e não é possível
    ter conhecimento técnico aprofundado em todas as áreas.

    Embora a decisão do Tribunal de Justiça do Estado
    de São Paulo tenha sido recebida com hostilidade pelos
    usuários da Internet, deve-se ressaltar sua importância,
    inclusive pela repercussão alcançada mundialmente.

    As questões ligadas ao direito da tecnologia da informação
    estão presentes no nosso cotidiano, o que significa que,
    cedo ou tarde, chegarão ao Judiciário.
    Prova disso é que cada vez mais os ilícitos eletrônicos
    têm ocupado as pautas de julgamento e os noticiários
    de jornais, rádios e emissoras de TV. Sendo assim, torna-se
    importante a discussão doutrinária, jurisprudencial
    e até mesmo legislativa em torno do tema.

    O “bloqueio” do “YouTube” foi determinado
    pelo Desembargador Ênio Santarelli, do TJ-SP, gerando várias
    discussões, inclusive acerca da territorialidade da lei
    e de decisões judiciais – ou seja, questionar se a justiça
    brasileira poderia bloquear total ou parcialmente conteúdo
    de sites hospedados no exterior. Não tenho dúvida
    de que a decisão foi acertada. Quando se considerar que
    há ofensa ao direito protegido em nosso território,
    a Justiça pode impedir que usuários tenham acesso
    ao conteúdo ilícito.

    O bloqueio total se dá através  do backbone,
    que  é o equipamento que faz a conexão da
    internet entre o Brasil e o mundo. Tendo em vista que o objeto
    da ação refere-se tão somente ao vídeo
    que exibe cenas de Daniela Cicarelli e do empresário Renato
    Malzoni Filho, o correto é que seja bloqueado o acesso
    ao referido conteúdo.

    Embora a decisão tal como proferida tenha causado o bloqueio
    total ao site, o desembargador, acertadamente, proferiu
    despacho elucidando que a determinação havia
    sido para que fosse empregado um filtro que impedisse o acesso
    ao vídeo do casal, indicando que o bloqueio total provavelmente
    ocorreu por dificuldades técnicas. Também foi determinada
    a expedição de contra-ordem para desbloquear o
    site “YouTube” e manteve a determinação
    da adoção de providências para bloquear o
    acesso às imagens sem acarretar não interdição
    do site completo.

    Ainda que cumprida a decisão judicial, tal qual proferida,
    isto não assegura que o vídeo não continue
    circulando pela Internet, visto que o “YouTube” e
    outros sites similares permitem que qualquer pessoa divulgue
    seus vídeos, em qualquer lugar do mundo. O desaparecimento
    dessas imagens vai depender de uma vigilância mais
    efetiva do referido site e de outros semelhantes para evitar a
    violação e a respectiva responsabilização
    e garantir os direitos dos autores da ação.

    Se quiserem, Daniella e seu namorado também podem entrar
    com uma ação contra quem efetuou a filmagem e contra
    quem a divulgou. Se há terceiros expondo cenas que violam
    esse direito à privacidade, eles também podem ser
    réus nas respectivas ações, respondendo
    cada um pelos danos que causar, podendo ingressar com pedido
    de tutela antecipada determinando que o filme não seja
    exibido, sob pena de multa diária.

    Toda essa polêmica pode servir como um incentivo para
    que os operadores do Direito encontrem alternativas que se enquadrem
    nesse novo cenário que a internet ocupa na vida das pessoas.
    A exposição de imagens e vídeos é apenas
    um dos problemas que a rede permite. Também há demanda
    para a vigilância e a punição de conteúdos
    racistas e pornográficos, contra ladrões cibernéticos
    e até medidas para assegurar a defesa dos consumidores
    na hora das compras eletrônicas. O debate está apenas
    começando.

  • IBM revela 5 inovações que poderão mudar nossas vidas nos próximos 5 anos

    Revelada
    pela primeira vez, a “IBM five in five” é uma lista de
    inovações baseada em tendências sociais e
    de mercado, que possivelmente irão transformar as nossas
    vidas nos próximos cinco anos. Na pesquisa
    também são contempladas as tecnologias emergentes
    dos Laboratórios da IBM que poderiam torná-las
    possíveis.
    Nos próximos cinco anos, de acordo
    com o estudo, as nossas vidas mudarão por meio das seguintes
    inovações tecnológicas:

    Seremos capazes de monitorar a nossa saúde
    remotamente

    Milhões de pessoas com problemas de saúde, como
    o diabetes, arritmia cardíaca, problemas de circulação
    etc, serão capazes de monitorar diariamente e automaticamente
    as suas condições de saúde de forma remota. Médicos,
    hospitais e clínicas terão uma atitude pró-ativa
    a todo momento, monitorando remotamente os seus pacientes e permitindo
    que alguns tratamentos sejam realizados em casa.
    Com isso,
    os pacientes terão a possibilidade de acompanhar melhor
    a sua própria saúde e as clínicas aumentarão
    a sua capacidade de prestar serviços de prevenção
    onde o paciente estiver.

    Telefones celulares lerão mentes

    A tecnologia de “presença” avançada irá conceder
    aos telefones e PDAs a habilidade de aprender automaticamente
    sobre o ambiente e preferências de seus usuários
    ao se deslocarem, seja a trabalho ou em viagens. Essa tecnologia,
    usada em mensagens instantâneas, já torna possível
    identificar e localizar um usuário assim que ele se conecta
    a rede. Em cinco anos, a nova infra-estrutura
    irá caracterizar fortes capacidades de aprendizagem de
    máquinas e reconhecimento de padrões.
    As
    novas redes permitirão que dispositivos aprendam a antecipar
    as preferências do usuário e a disponibilizar serviços
    através de todas as faixas do espectro wireless de 3G
    e GSM até RFID e Wi-fi.

    Novas tecnologias abordarão questões
    referentes ao Meio ambiente

    Governos e empresas buscam cada vez mais formas de trabalhos
    menos agressivas ao meio ambiente, trabalhando para assegurar
    a continuidade de recursos, como água, energia e etc. A
    nanotecnologia, habilidade de manipular átomos e moléculas
    individuais para formar novas estruturas minúsculas, finalmente
    teve um grande impacto em micro chips, fazendo com que produtos
    como PCs, celulares e PDAs fiquem menores, melhores e mais baratos.

    Nos
    próximos anos, a nanotecnologia irá gerar formas
    totalmente novas de memórias, melhorando os sistemas e
    permitindo que armazenem uma quantidade muito grande de informação,
    além de fornecer capacidade de “ligar instantaneamente”.
    Mas o uso da nanotecnologia também irá se expandir
    para outras aplicações além de eletroeletrônicos. Uma
    possibilidade interessante é o uso das nano partículas
    para a filtragem da água.
    Isso poderia promover
    a ecologia e a conservação, ajudando a tratar da
    falta de água potável mundialmente crescente.

    Tradução em tempo real

    O movimento em direção a globalização
    nos obriga a retomar aspectos básicos da humanidade, como
    a diferença de idiomas. As inovações de
    reconhecimento de voz da IBM permitem monitorar em inglês
    as transmissões de notícias em Chinês ou Árabe,
    através da web. Permitem aos viajantes com PDAs traduzirem
    seus menus de japonês e aos médicos que falam Inglês
    a comunicar-se com seus pacientes em espanhol. As
    tecnologias de tradução em tempo real estarão
    presentes em telefones celulares, carros e etc.
    Essas
    tecnologias estarão disponíveis em todos os setores
    dos negócios e da sociedade, eliminando as barreiras de
    idioma na economia global e facilitando a interação
    social.

    Internet 3D

    Os
    populares mundos on-line, tais como Second life e World of
    Warcraft, envolverão a Internet 3D.
    Nesse mundo on-line, você caminhará por corredores
    de supermercados, livrarias e lojas de DVDs, onde encontrará especialistas
    que você raramente encontraria na sua loja.
    A
    internet 3D possibilitará novas formas de e-learning,
    medicina a distância e experiências de consumidores
    interativas, transformando a forma como interagimos com nossos
    amigos e família, assim como negócios governamentais
    e instituições de serviços de saúde.

  • Apple apresenta Apple TV e iPhone

    Aconteceu ontem,
    na cidade de São Francisco, mais uma edição
    da famosa MacWorld Expo. Mais uma vez no keynote principal,
    o chariman Steve Jobs faz seu discurso. Dentre as grandes novidades
    anunciadas até o momento estão o tão aguardado
    iPhone e iTv.

    Sob uma chuva de aplausos, Steve Jobs iniciou sua apresentação
    comentando sobre a transição para processadores
    Intel, dizendo ser a melhor da história, uma vez que metade
    das vendas de 2006 foram feitas a usuários que nunca haviam
    comprado Mac.

    Jobs aproveitou a oportunidade mostrando números da iTunes
    Store numa tentativa de desmentir as notícias de que as
    vendas haviam caído. Em quantidade, afirma que vendem
    mais que a Amazon.

    A Apple MacWorld Expo 2007 acontece durante toda a semana, todavia
    o impacto já pode ser sentido no mercado de ações
    chegando a máxima de 92.75, e, juntamente com a Intel
    que anunciou o lançamento de sua nova linha de processadores
    – intel Core 2 Quad -, lidaram o top das ações
    mais negociadas na Nasdaq.

    O iPhone (u$ 499) 4GB /Us 599 8 GB tem tela
    widscreen sensível ao toque, combinado ao sistema telefônico
    e um comunicador web. Possui apenas um botão em sua parte
    frontal. Dentre suas funcionalidades, caso o usuário esteja
    escutando música e recebe uma ligação, basta
    aproximar o aparelho ao ouvido para o som da música ser
    desligado.

    O fone de ouvido do novo iPhone é no padrão sem
    fio Bluetooth. A bateria tem duração de cinco horas,
    e o usuário pode ficar escutando música por 16
    horas seguidas. Na versão mais básica serão
    duas. Sistema OS X Tela 3.5", 160 ppi. 11,6 mm e c âmera
    2MP. O lançamento será em junho.

    O iTV (u$ 299) 720 HD video / 802.11 wifi começa
    a ser comercializado em fevereiro com venda imediata. Os usuários
    poderão assistir e ouvir os seus vídeos, músicas
    ou fotografias sem precisar de um computador.

    "A Apple TV é o leitor de DVD do século XXI",
    indicou Stive Jobs. Ela terá um disco rígido de
    40 gigabytes, podendo armazenar até 50 horas de filmes,
    9 mil músicas ou 25 mil fotografias, com um processador
    Intel e uma resolução vídeo de alta definição
    de 720 pixels.

  • Notícias atualizadas com Feed e Ajax

    Olá amigos que acompanham a seção ASP.
    Neste artigo será desenvolvido um pequeno
    sistema de notícias
    atualizadas automaticamente baseando-se no sistema de RSS Feed
    da Folha de São Paulo e utilizando a tecnologia Ajax na
    leitura das notícias.

    Informo aos amigos desenvolvedores que este é um exemplo
    concatenado especificadamente com os feeds da Folha. Se algum
    desenvolvedor por ventura adicionar outros canais, terão
    que realizar alterações no script.

    Então mãos a obra. Abaixo segue o código
    comentado linha a linha para fácil entendimento de como
    o script foi concatenado.

    Crie um arquivo chamado “lendo.asp” e cole o código
    no arquivo criado.

    <%
    ‘Declaramos todas as variáveis
    que iremos utilizar em nosso script.
    Dim arrCanaisFolha(19), i, QueryString_UrlFeed, feed_selected,
    codFeed, endFeed, ArrUrl, creditos

    ‘Variável que será alimentada pelo código
    do canal do feed
    QueryString_UrlFeed = Request.QueryString("UrlFeed")
    ‘Declaramos uma constante indicando que
    as notícias do
    feed começam do 8º nó do xml.

    Const Nodo_Inicial = 8

    ‘Gravamos em um array todos os canais de rss da folha.
    ‘Observe que depois das descrições, temos o caracter
    _ (underline), o caracter separa a descrição do
    endereço do feed, abaixo utilizarei a função
    Split para separar os dados

    arrCanaisFolha(0) = "Brasil_brasil"
    arrCanaisFolha(1) = "Ci&ecirc;ncia_ciencia"
    arrCanaisFolha(2) = "Colunas – Bras&iacute;lia Online_colunas/brasiliaonline"
    arrCanaisFolha(3) = "Colunas – Di&aacute;rio, Depress&atilde;o
    e Fama_colunas/diariodepressaoefama"
    arrCanaisFolha(4) = "Colunas – Futebol na Rede_colunas/futebolnarede"
    arrCanaisFolha(5) = "Colunas – Ooops!_colunas/ooops"
    arrCanaisFolha(6) = "Colunas – Regra 10_colunas/regra10"
    arrCanaisFolha(7) = "Cotidiano_cotidiano"
    arrCanaisFolha(8) = "Dinheiro_dinheiro"
    arrCanaisFolha(9) = "Educa&ccedil;&atilde;o_educacao"
    arrCanaisFolha(10) = "Em cima da hora_emcimadahora"
    arrCanaisFolha(11) = "Equil&iacute;brio_equilibrio"
    arrCanaisFolha(12) = "Especial – 2006 – Copa_especial/2006/copa"
    arrCanaisFolha(13) = "Esporte_esporte"
    arrCanaisFolha(14) = "Ilustrada_ilustrada"
    arrCanaisFolha(15) = "Inform&aacute;tica_informatica"
    arrCanaisFolha(16) = "Mundo_mundo"
    arrCanaisFolha(17) = "Painel do Leitor_paineldoleitor"
    arrCanaisFolha(18) = "Pensata_pensata"
    arrCanaisFolha(19) = "Turismo_turismo"

    %>
    <html>
    <head>
    <style type="text/css">
    .link{font-family:arial; font-size:14px; color:black; text-decoration:none;}
    .link:hover{color:blue; text-decoration:underline;}
    </style>
    </head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
    <title>Leitor de RSS</title>
    <body leftmargin="0" topmargin="0" marginwidth="0" marginheight="0" onLoad="Ajax(‘conteudo_noticia’,’Ler_Noticia.asp?Nodo=<%=Nodo_Inicial%>’);">
    <script language="JavaScript" type="text/javascript" src="funcoes_ajax.js"></script>
    <script type="text/javascript" language="JavaScript">
    // Scripts do AJAX //
    var enableCache = false;
    var jsCache = new Array();
    var AjaxObjects = new Array();
                           
    function ShowContent(divId,ajaxIndex,url){
                document.getElementById(divId).innerHTML
    = AjaxObjects[ajaxIndex].response;
                 
                 if(enableCache){
                            jsCache[url]
    = AjaxObjects[ajaxIndex].response;
                 }         AjaxObjects[ajaxIndex]
    = false;
    }
                           
    function Ajax(divId,url){
                document.getElementById(divId).innerHTML
    = ‘<br><div align="center"><img src="aguarde.gif" width="16" height="16" vspace="2" /><font
    face="tahoma" size="2">&nbsp;&nbsp;Aguarde
    Carregando…</font></div><br><br>’;

                if(enableCache && jsCache[url]){
                            document.getElementById(divId).innerHTML
    = jsCache[url];
                            return;
                }         
               
                var ajaxIndex
    = AjaxObjects.length;
        AjaxObjects[ajaxIndex] = new sack();
        AjaxObjects[ajaxIndex].requestFile = url;
        AjaxObjects[ajaxIndex].onCompletion = function(){ ShowContent(divId,ajaxIndex,url);
    };
        AjaxObjects[ajaxIndex].runAJAX();
    }

    function carrega_feed(){
                document.location.href=’Lendo.asp?UrlFeed=’
    + document.frm_feed.endereco_feed.value;
    }
    </script>
    <strong><font size="4" face="arial">LEITOR
    DE RSS FOLHA- AJAX</font></strong><br>
    <br>
    <table width="577" border="0" cellspacing="0" cellpadding="0">
      <form name="frm_feed" method="post" action="Lendo.asp">
        <tr>
          <td width="188"><font size="2" face="arial"><strong>Selecione
    o Canal Desejado:</strong></font></td>
          <td width="389"> <div align="left">
              <select name="endereco_feed" onChange="carrega_feed();">
                              <option>—
    Selecione —</option>
                              <%
                              ‘Abaixo
    montaremos um looping com a array de canais que gravamos acima.
                              ‘Utilizaremos
    LBound para pegar a menor dimensão do Array e
    UBound para pegar a maior
    dimensão do Array
                              For
    i = LBound(arrCanaisFolha) To UBound(arrCanaisFolha)
                                        ‘Geramos
    um array baseando-se na função Split, como citado acima separaremos
    a descrição do endereço do feed.

                                        ArrCombo
    = Split(arrCanaisFolha(i),"_")

                                        ‘Verificamos
    se o código do canal atual é o mesmo do looping,
    quando a condição for verdadeira selecionaremos
    o canal com a variável feed_selected

                                        If
    CStr(QueryString_UrlFeed) = CStr(i) Then
                                                    feed_selected
    = "selected"
                                        Else
                                                    feed_selected
    = Null
                                        End
    If
                                        ‘Exibimos
    as opções do listbox no browser, a variável i representa
    a contagem do looping, o ArrCombo(0), indica ao sistema para pegar a descrição
    do array.

                                        ‘Acima
    separamos com a função Split, exemplo quando ArrCombo(0) for
    de dimensão 0 a descrição é exibida, quando ArrCombo(1)
    for de dimensão 1 o endereço do feed é exibido.

                                        Response.Write "<option
    value=""" & i & """ " & feed_selected & ">" & ArrCombo(0) & "</option>"
                              ‘Terminamos
    o looping com o comando Next

                              Next
                              %>
              </select>
            </div></td>
        </tr>
      </form>
    </table>
    <br>
    <%
    ‘Verificamos nesta condição se a variável
    QueryString_UrlFeed, contem um valor numérico caso a mesma
    não contenha, pegamos o primeiro canal do feed.

    If Not IsNumeric(QueryString_UrlFeed) = True Then
               
    Nesta condição a variável codFeed, com valor 0 seleciona
    o primeiro canal do feed.

                codFeed
    = 0
    Else
               
    Nesta condição a variável codFeed, pega o valor numérico
    da variável QueryString_UrlFeed

                codFeed
    = QueryString_UrlFeed
    End If

    ‘Geramos um array com a função Split, para pegarmos
    o endereço do feed.

    ArrUrl = Split(arrCanaisFolha(codFeed),"_")

    ‘Instanciamos o componente XMLHTTP, para realizarmos a consulta
    no site da folha
    Set objXMLHttp = Server.CreateObject("Microsoft.XMLHTTP")
    ‘Observe que o array ArrUrl(1) está com dimensão
    1, o que significa que iremos trazer o endereço do feed.
    ‘Abriremos a solicitação do XMLHTTP.

    objXMLHttp.Open "GET", "http://feeds.folha.uol.com.br/folha/" & ArrUrl(1) & "/rss091.xml",
    False
    ‘Informaremos no cabeçalho de nossa solicitação
    que o conteúdo do arquivo é XML

    objXMLHttp.setRequestHeader "Content-Type","text/xml"
    ‘Enviamos a solicitação
    objXMLHttp.Send()

    ‘Verificamos se a solicitação retornou o status
    200, processado com êxito.

    If objXMLHttp.Status = 200 Then
                ‘Instanciamos
    o componente XMLDOM para iniciarmos a leitura dos dados.

                Set objXML
    = Server.CreateObject("Microsoft.XMLDOM")
                ‘
                objXML.async
    = False
                ‘Carregamos
    o conteúdo retornado pelo componente XMLHTTP.

                objXML.loadXML(objXMLHttp.responsexml.xml)
               
                ‘Verificamos
    se o arquivo XML não possue erros.

                If objXML.parseError.errorCode <> 0
    Then
                            ‘Caso
    possua algum erro, exibimos o erro no browser

                            Response.Write
    objXML.parseError.reason
                Else
                            ‘Criamos
    um objeto chamado raiz para exibirmos os dados

                            Set
    raiz = objXML.documentElement
                           
                            ‘Iniciaremos
    um looping para exibir as notícias retornadas pelo xml, pegaremos o
    valor do Nodo_inicial e contaremos todos os Nodos subtraindo pelo Nodo_Inicial.
                            ‘Com
    isso iremos obter o valor do primeiro nó que contém a notícia
    até o ultimo nó de notícias.

                            For
    i = Nodo_Inicial To raiz.childNodes.Item(0).childNodes.length – Nodo_Inicial
                                        ‘Exibimos
    os titulos da notícia para o browser.

                                        Response.Write "<a
    class=""link"" href=""javascript:Ajax(‘conteudo_noticia’,’Ler_Noticia.asp?Nodo=" & i & "’);"">&raquo;&raquo; " & raiz.childNodes.Item(0).childNodes.Item(i).childNodes.Item(0).Text & "</a><br>"
                                        ‘Gravamos
    em um session o título da noticia para exibirmos no arquivo de visualização
    da notícia

                                        Session("titulo_" & i)
    = raiz.childNodes.Item(0).childNodes.Item(i).childNodes.Item(0).Text
                                        ‘Gravamos
    em um session o conteúdo da noticia para exibirmos no arquivo de visualização
    da notícia

                                        Session("noticia_" & i)
    = raiz.childNodes.Item(0).childNodes.Item(i).childNodes.Item(2).Text
                            Next
                                        ‘Variável
    que contém os creditos existentes no Feed da Folha

                                        creditos
    = "<font face=""tahoma"" size=""1"">" & raiz.childNodes.Item(0).childNodes.Item(0).childNodes.Item(0).Text & " – "  & raiz.childNodes.Item(0).childNodes.Item(4).childNodes.Item(0).Text & "</font>"
                           
                            ‘Destruimos
    o objeto raiz

                            Set
    raiz = Nothing      
                            ‘Destruimos  instância
    ao componente XMLDOM

                            Set
    objXML = Nothing
                End If
    Else
                ‘Informamos
    no browser que ocorreu um erro durante o processo.

                Response.Write "Erro
    ao processar solicitação…"
                ‘Paramos
    o programa

                Response.End
    End If

    ‘Destruimos a instância ao componente
    XMLHTTP

    Set objXMLHttp = Nothing
    %>
    <br>
    <table width="577" height="223" border="0" cellpadding="0" cellspacing="0" style="border:1px
    solid black;">
      <tr>
        <td width="577" height="221" valign="top"><div
    id="conteudo_noticia"></div></td>
      </tr>
    </table>
    <%
    ‘Exibimos os créditos existentes no RSS da Folha.
    Response.Write creditos
    %>
    </body>
    </html>

    Observe que, nas primeiras tags HTML, o script realiza a chamada
    em um arquivo chamado “funções_ajax.js”.
    Utilizo este bloco de funções pois, além
    de facilitar a ligação com AJAX, também
    o instânciamento do XMLHTTP torna-se compatível
    com todos browsers. Esse arquivo de funções é muito útil para
    trabalharmos com AJAX.

    Próximo passo: crie um arquivo chamado “lendo_noticia.asp” e
    cole o código abaixo.

    <%
    ‘Variável responsável pelo código da notícia
    QueryString_Nodo = Request.QueryString("Nodo")

    ‘Verificamos se o código da notícia possue valor
    numérico.

    If Not IsNumeric(QueryString_Nodo) = True Then
                ‘Caso
    a variável não possua valor numérico, exibimos o erro no
    browser.

                Response.Write "Erro
    ao carregar notícia!!!"
                ‘Paramos
    o programa

                Response.End
    End If

    ‘Função responsável por transformar códigos
    em HTML

    Function TransformaHTML(strHTML)
                strHTML
    = Replace(strHTML, "&lt;","<")
                strHTML
    = Replace(strHTML, "&gt;",">")
                strHTML
    = Replace(strHTML, "&quot;","""")
                strHTML
    = Replace(strHTML, "<a ","<a target=""_blank"""" ")
                TransformaHTML
    = strHTML
    End Function

    ‘Exibimos a notícia no browser, note que utilizei a opção
    Server.HTMLEncode, para codificar a solicitação
    em HTML, pois quando não estava utilizando estive com
    problemas de acentuação na solicitação
    em AJAX, neste caso os acentos são transformados em código
    no HTML, e a função TransformaHTML(), é reponsável
    de separar o texto de tags html.

    Response.Write "<font face=""arial"" size=""2""><div
    align=""center""><strong>" & TransformaHTML(Server.HTMLEncode(Session("titulo_" & QueryString_Nodo))) & "</strong></div><br>" & TransformaHTML(Server.HTMLEncode(Session("noticia_" & QueryString_Nodo))) & "</font>"
    %>

    Próximo passo: crie um arquivo chamado “funcoes_ajax.js”,
    cole o código no arquivo criado.

    /* Simple AJAX Code-Kit (SACK) v1.6.1 */
    /* ©2005 Gregory Wild-Smith */
    /* www.twilightuniverse.com */
    /* Software licenced under a modified X11 licence,
       see documentation or authors website for more details */

    function sack(file) {
    this.xmlhttp = null;

    this.resetData = function() {
    this.method = "POST";
      this.queryStringSeparator = "?";
    this.argumentSeparator = "&";
    this.URLString = "";
    this.encodeURIString = true;
      this.execute = false;
      this.element = null;
    this.elementObj = null;
    this.requestFile = file;
    this.vars = new Object();
    this.responseStatus = new Array(2);
      };

    this.resetFunctions = function() {
      this.onLoading = function() { };
      this.onLoaded = function() { };
      this.onInteractive = function() { };
      this.onCompletion = function() { };
      this.onError = function() { };
    this.onFail = function() { };
    };

    this.reset = function() {
    this.resetFunctions();
    this.resetData();
    };

    this.createAJAX = function() {
    try {
    this.xmlhttp = new ActiveXObject("Msxml2.XMLHTTP");
    } catch (e1) {
    try {
    this.xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    } catch (e2) {
    this.xmlhttp = null;
    }
    }

    if (! this.xmlhttp) {
    if (typeof XMLHttpRequest != "undefined") {
    this.xmlhttp = new XMLHttpRequest();
    } else {
    this.failed = true;
    }
    }
    };

    this.setVar = function(name, value){
    this.vars[name] = Array(value, false);
    };

    this.encVar = function(name, value, returnvars) {
    if (true == returnvars) {
    return Array(encodeURIComponent(name), encodeURIComponent(value));
    } else {
    this.vars[encodeURIComponent(name)] = Array(encodeURIComponent(value),
    true);
    }
    }

    this.processURLString = function(string, encode) {
    encoded = encodeURIComponent(this.argumentSeparator);
    regexp = new RegExp(this.argumentSeparator + "|" +
    encoded);
    varArray = string.split(regexp);
    for (i = 0; i < varArray.length; i++){
    urlVars = varArray[i].split("=");
    if (true == encode){
    this.encVar(urlVars[0], urlVars[1]);
    } else {
    this.setVar(urlVars[0], urlVars[1]);
    }
    }
    }

    this.createURLString = function(urlstring) {
    if (this.encodeURIString && this.URLString.length) {
    this.processURLString(this.URLString, true);
    }

    if (urlstring) {
    if (this.URLString.length) {
    this.URLString += this.argumentSeparator + urlstring;
    } else {
    this.URLString = urlstring;
    }
    }

    // prevents caching of URLString
    this.setVar("rndval", new Date().getTime());

    urlstringtemp = new Array();
    for (key in this.vars) {
    if (false == this.vars[key][1] && true == this.encodeURIString)
    {
    encoded = this.encVar(key, this.vars[key][0], true);
    delete this.vars[key];
    this.vars[encoded[0]] = Array(encoded[1], true);
    key = encoded[0];
    }

    urlstringtemp[urlstringtemp.length] =
    key + "=" +
    this.vars[key][0];
    }
    if (urlstring){
    this.URLString += this.argumentSeparator + urlstringtemp.join(this.argumentSeparator);
    } else {
    this.URLString += urlstringtemp.join(this.argumentSeparator);
    }
    }

    this.runResponse = function() {
    eval(this.response);
    }

    this.runAJAX = function(urlstring) {
    if (this.failed) {
    this.onFail();
    } else {
    this.createURLString(urlstring);
    if (this.element) {
    this.elementObj = document.getElementById(this.element);
    }
    if (this.xmlhttp) {
    var self = this;
    if (this.method == "GET") {
    totalurlstring = this.requestFile + this.queryStringSeparator
    + this.URLString;
    this.xmlhttp.open(this.method, totalurlstring, true);
    } else {
    this.xmlhttp.open(this.method, this.requestFile, true);
    try {
    this.xmlhttp.setRequestHeader("Content-Type", "application/x-www-form-urlencoded")
    } catch (e) { }
    }

    this.xmlhttp.onreadystatechange = function() {
    switch (self.xmlhttp.readyState) {
    case 1:
    self.onLoading();
    break;
    case 2:
    self.onLoaded();
    break;
    case 3:
    self.onInteractive();
    break;
    case 4:
    self.response = self.xmlhttp.responseText;
    self.responseXML = self.xmlhttp.responseXML;
    self.responseStatus[0] = self.xmlhttp.status;
    self.responseStatus[1] = self.xmlhttp.statusText;

    if (self.execute) {
    self.runResponse();
    }

    if (self.elementObj) {
    elemNodeName = self.elementObj.nodeName;
    elemNodeName.toLowerCase();
    if (elemNodeName == "input"
    || elemNodeName == "select"
    || elemNodeName == "option"
    || elemNodeName == "textarea") {
    self.elementObj.value = self.response;
    } else {
    self.elementObj.innerHTML = self.response;
    }
    }
    if (self.responseStatus[0] == "200") {
    self.onCompletion();
    } else {
    self.onError();
    }

    self.URLString = "";
    break;
    }
    };

    this.xmlhttp.send(this.URLString);
    }
    }
    };

    this.reset();
    this.createAJAX();
    }

    Pronto! Salve os arquivos e execute o projeto!

  • Data Mining na Prática: Time Series

    Olá pessoal. Nesta coluna vamos continuar nosso estudo
    sobre algoritmos de Data Mining. Desta vez abordaremos o algoritmo
    que trabalha com a predição de valores em uma série
    temporal, o algoritmo de Time Series. Para a implementação
    do exemplo utilizarei o Analisys Services 2005, pois o algoritmo
    de Data Mining para séries temporais é uma das
    novas funcionalidades.

    Antes de começar a verificar os detalhes do algoritmo,
    vamos entender como os dados estão organizados em uma
    série temporal. Geralmente os dados de uma série
    temporal são indexados por um período de tempo
    com intervalos fixos como, por exemplo, dados armazenados mensalmente
    ou diariamente. Em séries de dados temporais é comum
    encontrar valores que variam no tempo, sendo que a principal
    característica dos dados de uma série temporal
    na regularidade dos períodos.

    Os dados de uma série temporal podem conter mais de um
    conjunto de dados. Por exemplo, uma única série
    temporal pode conter a quantidade de estoque de um produto e
    a quantidade vendida deste mesmo produto. Os algoritmos que trabalham
    com a predição de valores de séries temporais
    geralmente trabalham com apenas um conjunto de dados por vez.
    Já o algoritmo de séries temporais do Analisys
    Services 2005 permite que se trabalhe com mais de um conjunto
    de dados, de modo que a identificação de correlações
    entre estes conjuntos para ajudar na predição.
    Este tipo de correlação entre conjuntos de dados
    de uma série temporal é chamado de cross prediction.

    Outro conceito importante sobre séries temporais é a
    sazonalidade. Este conceito pode ser definido da seguinte maneira:
    os dados de uma série temporal apresentam padrões
    de comportamento que se repetem durante os períodos da
    série. Um exemplo de sazonalidade pode ser o aumento de
    temperatura nos meses de verão em uma série temporal
    que armazena a temperatura mês a mês. O aumento de
    temperatura, neste caso, provavelmente vai se repetir em todos
    os meses de verão, independente do ano, demonstrando a
    sazonalidade do aumento da temperatura.

    Os algoritmos de Data Mining para séries temporais são
    utilizados para prever novos dados a partir dos dados históricos
    da série. Ou seja, o algoritmo vai analisar a quantidade
    de dados existentes e fornecer uma possível previsão
    do que pode acontecer nos próximos períodos. Esta
    previsão leva em consideração os dados ‘passados’ da
    série temporal, que se tornam seu conjunto de treinamento.
    A previsão fornecida pelos algoritmos de Data Mining para
    series temporais é baseada em regressões não-lineares.
    Cabe a usuário apenas fornecer a série temporal
    e especificar quais os períodos o algoritmo deve prever.

    Um ponto importante a ser considerado é a qualidade da
    predição. Podemos utilizar este algoritmo para
    prever o valor da cotação de uma determinada empresa
    e ficarmos ricos? Infelizmente a resposta é não.

    A qualidade da predição é um assunto delicado
    quando se fala em algoritmos para séries temporais. É importante
    lembrar que a previsão é apenas UMA possibilidade
    e que geralmente os algoritmos de séries temporais tendem
    a apresentar previsões razoáveis, previsões
    estas que levam em consideração diversos fatores
    como, por exemplo, a correlação com outras séries
    e a sazonalidade. Estes algoritmos trabalham com modelos para
    representar os dados e, em algumas situações, é mais
    recomendado elaborar um modelo específico para a série
    temporal do que utilizar um algoritmo de Data Mining. No exemplo
    da cotação faz mais sentido procurar um modelo
    específico para sistemas caóticos do que utilizar
    um algoritmo de Data Mining para séries temporais.

    Apresentadas estas características, podemos começar
    a estudar o uso do algoritmo de séries temporais implementado
    no Analisys Services 2005. Este algoritmo é muito complexo
    e utiliza outro algoritmo de Data Mining, o algoritmo de árvores
    de decisão. Sem entrar em maiores detalhes do seu funcionamento,
    um exemplo simples será apresentado para demonstrar como
    este algoritmo pode ser empregado. Para os leitores que desejarem
    maiores informações, recomendo uma boa lida no
    artigo que explica os detalhes do funcionamento do algoritmo.
    Este artigo pode ser visto por meio do link abaixo:

    http://go.microsoft.com/fwlink/?LinkId=45966

    Prevendo a quantidade de venda de vinhos

    A uma série temporal do nosso exemplo traz a quantidade
    de litros de um determinado tipo de vinho (em milhares de litros)
    vendidos mês a mês durante janeiro de 1950 e julho
    de 1995. Estes dados foram retirados da biblioteca de séries
    temporais criada por Rob Hyndman, disponível no link abaixo:

    http://www-personal.buseco.monash.edu.au/~hyndman/TSDL/

    A série temporal utilizada neste exemplo contém
    apenas um conjunto de dados: a quantidade de litros de vinho
    vendida. A Figura 1 apresenta um gráfico com os valores
    da série temporal.

    Figura 1. Gráfico com as vendas de milhares de litros
    de vinho por mês.

    O objetivo do uso do algoritmo para séries temporais é prever
    qual será a quantidade de litros de vinho vendida nos últimos
    meses de 1995 e nos anos de 1996 e 1997. Apesar de contar com
    dados antigos, esta série temporal apresenta boas informações
    para um exemplo didático.

    Vamos utilizar o algoritmo de séries temporais do Analisys
    Services 2005 para elaborar a previsão desejada. É importante
    lembrar que este algoritmo pode ser utilizado apenas nas edições
    Standard e Enterprise do SQL Server 2005 e que é necessária
    a instalação do SQL Server 2005 e do Analisys Services
    2005 para o uso deste algoritmo.

    O primeiro passo é armazenar os dados em uma tabela
    do SQL Server 2005. Vamos supor que todos os dados desta série
    temporal estão armazenados em uma tabela chamada TB_VENDAS_VINHO,
    que contém as colunas DATA e QTD_VENDIDA, e que esta tabela
    está armazenada no banco de dados chamado DB_TIME_SERIES.
    No final do artigo serão disponibilizados para download
    os dados e os scripts utilizados.

    Com os dados já armazenados é necessário
    configurar o Analisys Services para que ele possa obter os dados
    por meio de um provider OLE DB. A Figura 2 apresenta a janela
    de configuração do Analisys Services, obtida a
    partir do clique com o botão direito do mouse no servidor
    Analisys Services dentro do Management Studio 2005.

    Figura 2. Opções de configuração
    do Analisys Services.

    Basta modificar os valores das opções em destaque
    na Figura 2 para que o Analisys Services possa acessar os dados
    por meio de um provider OLE DB. A opção AllowedProvidersInOpenRowset deve
    conter o valor [All] digitado na coluna Value e as demais opções
    devem conter o valor true. Não se esqueçam de selecionar
    a caixa de texto Show Advanced (All) Properties para
    poderem ter acesso a todas as propriedades.

    Uma vez que o servidor esteja configurado podemos montar o Modelo
    de Mineração (Mining Model) que será utilizado
    pelo algoritmo de séries temporais. Para isso devemos
    criar uma nova Query DMX (Data Mining Extensions). Estas queries
    DMX são como a linguagem Transact-SQL, porém o
    DMX é uma linguagem específica para o uso de Data
    Mining no SQL Server 2005. Para iniciar uma nova query DMX basta
    clicar no menu File do Management Studio, escolher a opção
    New e a sub-opção New Analisys Services DMX Query.
    Em seguida é necessário fornecer um login e senha
    para o servidor Analisys Services. Cuidado com as informações
    fornecidas nesta tela de login: NÃO é um login/senha
    do SQL Server (engine) e sim um login/senha do Analisys Services!

    O próximo passo para a execução do algoritmo é criar
    o modelo de mineração e importar os dados da tabela
    TB_VENDAS_VINHO. Para criar o modelo de mineração é necessário
    utilizar o comando CREATE MINING MODEL. Para importar os dados
    devemos utilizar a instrução INSERT INTO junto
    com a função OPENROWSET() que apontará para
    o servidor que contém o banco de dados TB_TIME_SERIES
    e a tabela TB_VENDAS_VINHO. Após a criação
    do modelo e a importação dos dados vamos indicar
    ao algoritmo que ele deve prever os próximos 29 valores
    da série temporal, referentes aos 5 próximos meses
    de 1995 e aos 24 valores dos meses de 1996 e 1997. A função PredictTimeSeries() será utilizada
    em uma instrução SELECT que acessa os dados do
    modelo de mineração. A Figura 3 apresenta as instruções
    para a criação do modelo, a importação
    dos dados e a query que faz a previsão dos novos valores.

    Figura 3. Criação do modelo de mineração,
    importação dos dados e predição dos
    valores.

    O resultado da execução da instrução
    SELECT que faz a predição dos dados é apresentado
    como uma tabela interna e não como um conjunto de linhas
    de colunas. Se o desenvolvedor desejar trabalhar com a manipulação
    destes resultados em uma aplicação basta procurar
    na documentação do .NET Framework por classes e
    métodos relacionados ao uso dos algoritmos de Data Mining.
    Para mais informações sobre estes recursos eu recomendo
    uma boa lida na documentação do SQL Server 2005,
    o Books OnLine.

    Inserindo no gráfico os dados gerados pela execução
    do algoritmo de série temporais pode-se fazer uma análise
    mais detalhada dos novos valores . A Figura 4 apresenta o gráfico
    contendo os novos valores para a quantidade de vinho vendida.

    Figura
    4. Vendas de milhares de litros de vinho por mês.

    Analisando os dados previstos pelo algoritmo, podemos ver que
    a previsão segue o padrão de vendas histórico,
    onde há uma queda significativa nas vendas nos primeiros
    meses dos anos (Janeiro e Fevereiro) e o crescimento das vendas
    nos meses da metade do ano (Julho e Agosto). Para uma análise
    mais detalhada do motivo destas quedas e crescimentos é necessário
    contar com a ajuda de um especialista no domínio. Contudo,
    o algoritmo prevê uma continuidade deste comportamento.
    A previsão forneceu valores aproximados, mas não
    iguais. Outro detalhe que pode ser observado no gráfico é descontinuidade
    dos valores entre o que é histórico e o que é previsto.
    Esta descontinuidade foi deixada de propósito para separar
    os dados históricos dos dados que foram previstos pelo
    algoritmo.

    Para fazer o download dos dados e dos scripts utilizados nesta
    coluna clique aqui.

    Um grande abraço e até a próxima coluna.

  • Coleção de FLAs – Parte 03

    Acompanhe a terceira
    relação da coleção de trabalhos
    em Flash, acompanhados por seus respectivos .FLAs, para estudo.
    Se algum leitor desejar colaborar, ou queira solicitar algum
    exemplo, favor entrar em contato.

    CSS via ActionScript (download
    do arquivo .FLA
    )




    Cursos no Start Drag
    (download
    do arquivo .FLA
    )




    Data e Hora
    (download
    do arquivo .FLA
    )




    Detector de Colisão
    (download
    do arquivo .FLA
    )



    Abraços!

  • Unificando bases de dados com Schemas

    Aqui explico como organizar diversos bancos de dados PostgreSQL utilizando o conceito de Schemas. A idéia é centralizar varias bases de sistemas distintos em um único banco, centralizando todo o seu gerenciamento. Neste processo iremos:

    . Criar um novo banco de dados destinado a ser o "Banco de Dados Central";
    . Criar tablespaces para tabelas e índices e fazer com que todos os índices e tabelas de todos os sistemas armazenem seus dados nas suas respectivas tablespaces;
    . Centralizar toda a codificação de caracteres para todos os sistemas em UTF8;
    . Utilizar apenas um usuário administrador, o postgres para todos os sistemas;
    . Utilizar um usuário e um schema com o mesmo nome para cada sistema a ser utilizado pelo desenvolvedor para criar os objetos do sistema;
    . Utilizar um ou mais usuários para a aplicação com permissões restritas em cada objeto a ser utilizado;

    Para isto, utilizaremos o PostgreSQL 8.1 rodando em Linux. No entanto, a maioria das coisas aqui descritas se aplicam a outros sistemas operacionais no padrão POSIX (linux, BSDs, Solaris, etc) e versões 8.x do PostgreSQL.

    Parte I – Preparação

    01. Criar tablespaces:
    Antes mesmo de criar nosso banco de dados centralizado, criaremos os tablespaces a serem utilizados. Mesmo que você não possua vários discos ou arrays distintos para armazenar os seus dados, é importante já começar a preparar os seus sistemas para isto. Conforme eles crescem, você deverá precisar de mais storage. Separar os logs, tabelas e índices e unidades físicas distintas costuma ser a providência número um para aumentar a performance. É claro que sistemas maiores podem utilizar tablespaces separados para cada sistema ou para tabelas e índices com dados históricos (utilizando o particionamento de tabelas) para aumentar ainda mais o desempenho. Como nosso tópico principal aqui não é o tunning, não nos aprofundaremos no assunto aqui.

    Criaremos as seguintes tablespaces básicas:

    – Uma tablespace para tabelas chamada tbs_tables
    – Uma tablespace para índices chamada tbs_indexes

    Antes de criar sua tablespace, você deve entender que o PostgreSQL 8.x trata cada tablespace como um diretório no seu sistema de arquivos. Portanto, é preciso criar os diretórios no seu sistema operacional antes de criar os tablespaces. Também é preciso garantir a permissão de leitura e gravação nas pastas recém criadas. O local onde você irá criar seus tablespaces depende da forma como você deseja organizar sua estrutura de diretórios. Aqui, criaremos uma pasta específica para isso, na raiz. Na sua linha de comando digite:

    $ su
    # su postgres
    $ cd /
    $ mkdir postgresql
    $ cd postgresql
    $ mkdir tablespaces
    $ cd tablespaces
    $ mkdir tables
    $ mkdir indexes

    Feito isto, você pode se conectar ao psql
    e criar os tablespaces:

    $ psql
    > CREATE TABLESPACE tbs_tables OWNER postgres LOCATION ‘/postgresql/tablespaces/tables’;
    > CREATE TABLESPACE tbs_indexes OWNER postgres LOCATION ‘/postgresql/tablespaces/indexes’;

    02. Criar o banco de dados central:
    Feito isto, criaremos o banco de dados que servirá para para centralizar todos os seus bancos de dados. Para isto utilizarei a opção ‘-D’ para definir um tablespace padrão a ser utilizado em todos os objetos que não especificarem um tablespace padrão. Outra opção importante é o ‘-E’ onde especifico o tipo de codificação de caracteres.

    $ createdb -D tbs_tables -E utf-8 nome_do_banco

    03. Criar
    role padrão para desenvolvedores:
    O próximo passo é criar um role que será utilizado por
    todos os usuários que poderão criar objetos no banco. Note que
    este role não será utilizado para se logar no banco e sim para
    que novos usuários herdem suas permissões. Concederemos permissão
    para:

    – Criar objetos no banco de dados recém criado;
    – Criar objetos nos tablespaces tbs_tables e tbs_indexes.

    > CREATE ROLE developer WITH NOLOGIN;
    > GRANT CREATE ON DATABASE nome_do_banco TO developer;
    > GRANT CREATE ON TABLESPACE tbs_tables TO developer;
    > GRANT CREATE ON TABLESPACE tbs_indexes TO developer;

    Parte II – Unificando os bancos de dados

    04. Fazer DUMP do banco de dados a ser migrado:
    A primeira coisa que você deve fazer agora é exportar cada banco de dados individual. A melhor forma de fazer isto é utilizando o pg_dump através da linha de comando. Você pode fazer alguns testes iniciais sem carregar a estrutura dos dados para ver se está tudo ok. Para isto, utilize a opção ‘-s’. Depois você pode exportar apenas os dados utilizando a opção ‘-a’.

    $ pg_dump –use-set-session-authorization -E utf-8 -h ip_do_banco -U postgres nome_do_banco_a_ser_migrado > nome_do_banco_a_ser_migrado.sql

    a opção ‘–use-set-session-authorization’ é opcional. Ela faz com que seja utilizada o comando SQL ‘SET SESSION AUTHORIZATION ‘ ao invés do ‘ALTER … OWNER’ para cada objeto. A opção ‘-E’ força a exportação ser realizada na codificação de caracteres desejada. Desta forma não é preciso utilizar o iconv ou mudar o ‘client enconding’ para importar os dados na codificação correta.

    05. Editar o dump:
    Agora vem a parte mais importante do processo de migração, editar o dump e corrigir algumas coisas:

    . Alterar o tablespace para as tabelas e índices com o comando SQL ‘ SET default tablespace’;

    . Criar o usuário que será dono do schema e todos os objetos dentro dele, a ser utilizado pelo desenvolvedor. Colocamos também um limite de conexões para este usuário para impedir que o desenvolvedor tente utilizar este usuário como usuário da aplicação;

    . Criar um ou mais usuários a serem utilizados pela aplicação;

    . Criar o schema e defini-lo como padrão para que todos os objetos subsequentes sejam criados dentro dele, através da instrução ‘ SET search path’;

    . Criar as permissões para os usuários das aplicações concedendo apenas os privilégios realmente necessários para eles.

    Alguns cuidados:

    . Utilize um editor em modo texto, principalmente se o seu dump for muito grande. Isto irá facilitar o seu trabalho de edição, pois abrir arquivos grandes em modo gráfico pode acabar com a memória do seu computador mais rápido do que em modo texto. Outra alternativa é criar um dump separado para a definição de dados DDL e outro para os dados em DML. A maior parte das alterações dizem respeito apenas a DDL, que são arquivos bem menores.

    . Verifique se existe uma linha igual a esta no início do arquivo:
    SET client_encoding = ‘utf-8’;
    ela é importante para garantir que o psql vá utilizar a codificação correta durante a importação. Caso você esteja utilizando outra codificação, você poderá ter problemas durante a importação. Mude a codificação de caractere para UTF8 ou mude o ‘client-encoding’ para aquele que o arquivo do dump está utilizando.

    . Algumas linhas como o ‘ SET default tablespace’ e ‘SET search path’ já vem no dump padrão realizado pelo pg_dump. Ao invés de reescrever estas linhas, apenas altere a já existente. O risco não fazê-lo é criar um parâmetro que será sobrescrito pré-existente no dump pouco após da linha que você acrescentou.

    . Algumas funções em PL são criadas dependendo da versão do PostgreSQL que você está utilizando. Estas funções costumam ser criadas ao se criar o banco de dados ou ao se implementar alguma funcionalidade do diretório contrib do PostgreSQL. Geralmente, estas funções são comuns a todos os sistemas e não precisam ser incluídas novamente. Costuma ser seguro remover estas linhas do dump. Caso ocorra algum problema durante a homologação, você poderá criar um novo dump e recuperar as funções da base de dados antiga.

    05.1 Criando usuários:

    CREATE ROLE sistema_a WITH LOGIN PASSWORD ‘123456’ INHERIT IN ROLE developer CONNECTION LIMIT 2;
    CREATE ROLE sistema_a_client WITH LOGIN PASSWORD ‘123456’;
    SET SESSION AUTHORIZATION sistema_a;

    Note aqui que o ‘INHERIT IN ROLE developer’ faz com que o usuário faça parte da role developer e ainda herde as permissões dele. A linha ‘ SET SESSION AUTHORIZAION’ faz com que os objetos subsequentes sejam todos criados com o usuário citado como owner.

    05.2 Criando o schema:
    Agora criaremos o schema com o mesmo nome do usuário do desenvolvedor. É importante que o usuário tenha o mesmo nome do schema, pois no arquivo postgresql.conf o ‘search_path’ inclui a variável ‘$user’ por default. Isto significa que o nome do usuário que se conectar procurará automaticamente objetos neste schema sem precisar qualificar seu nome ou utilizar o ‘SET search path’.

    CREATE SCHEMA sistama_a AUTHORIZATION sistema_a;

    05.3 Definido os tablespaces:
    Para definir o tablespace, você deve procurar dois pontos importantes no seu dump: o ponto imediatamente anterior antes de criar as tabelas e o ponto imediatamente anterior a criação dos índices e constraints.

    Antes da criação das tabelas coloque a seguinte linha:

    SET default_tablespace = ‘tbs_tables’;

    Antes da criação de índices e constraints, coloque a seguinte linha:

    SET default_tablespace = ‘tbs_indexes’;

    05.4 Concedendo privilégios aos usuários da aplicação

    No final do dump, o pg_dump coloca as permissões inerentes aos objetos criados para cada usuário. Esta parte do trabalho não tem como ser automatizada. É interessante manter o REVOKE para o usuário PUBLIC de forma a zerar as permissões para todos os usuários antes de concedê-las novamente. Evite a todo o custo conceder privilégios do tipo ALL, a fim de não conceder mais privilégio do que o estritamente necessário para cada usuário. Apesar de ser uma tarefa tediosa, esta é uma tarefa importante no trabalho de qualquer bom DBA. Privilégios do tipo CREATE, TEMP, DELETE, RULE, REFERENCES, TRIGGER que só devem existir em usuários de sistema em casos específicos.

    06. Importação: O último passo é importar cada dump devidamente alterado no passo anterior para o banco de dados central.

    $ psql -h ip_do_banco -U postgres nome_do_banco < nome_do_banco_a_ser_migrado.sql

    07. Testes:
    Por fim, deve-se testar a aplicação para que ver se tudo está funcionando adequadamente com o usuário do sistema e senha nova. Pode ser necessário qualificar o nome dos esquemas para acessar os objetos no local correto. Uma alternativa mais simples é utilizar a instrução ‘SET search path’ logo após a conexão com o banco de dados. Uma boa idéia é utilizar também a instrução ‘ SET client enconding’ utilizando a codificação da sua aplicação. Como o UTF8 tem a capacidade de ser convertido para a maior parte dos tipos de codificação, ele é ideal para ser utilizado no servidor, enquanto no cliente você pode escolher o tipo de codificação mais adequado para a sua aplicação.

    Lembre-se de testar cuidadosamente sua aplicação antes de libera-la para a produção. Um servidor de testes é fundamental para este processo.

    Referências:

    . Schemas: http://www.postgresql.org/docs/8.1/interactive/ddl-schemas.html
    . psql: http://www.postgresql.org/docs/8.1/interactive/app-psql.html
    . pg_dump: http://www.postgresql.org/docs/8.1/interactive/app-pgdump.html
    . CREATE DATABASE: http://www.postgresql.org/docs/8.1/interactive/sql-createdatabase.html
    . CREATE TABLESPACE: http://www.postgresql.org/docs/8.1/interactive/sql-createtablespace.html
    . CREATE SCHEMA: http://www.postgresql.org/docs/8.1/interactive/sql-createschema.html
    . CREATE ROLE: http://www.postgresql.org/docs/8.1/interactive/sql-createrole.html
    . GRANT: http://www.postgresql.org/docs/8.1/interactive/sql-grant.html
    . REVOKE: http://www.postgresql.org/docs/8.1/interactive/sql-revoke.html
    . SET: http://www.postgresql.org/docs/8.1/interactive/sql-set.html
    . SET AUTHORIZATION SESSION: http://www.postgresql.org/docs/8.1/interactive/sql-set-session-authorization.html

  • API do Windows é sua amiga

    Muitas vezes o programador acha que uma linguagem ou outra é fraca
    ou limitada simplesmente porque não encontrou uma função
    ou comando específico. Para escovadores de bits que já programaram
    por exemplo em Mumps (não aconselho, mas se quiser conhecer: http://mumps.sourceforge.net/docs.html#COMMANDS),
    sabem que as linguagens têm no máximo uns 30 comandos
    o resto são bibliotecas que devem ser criadas na unha
    e cada programador tinha sua caixa de ferramentas particular.
    Com o passar do tempo e para facilitar a vida dos programadores,
    as linguagem incorporaram mais e mais comandos e funções,
    embora linguagens como Java e .NET na verdade são praticamente
    bibliotecas de funções prontas que o programador
    apenas utiliza como repositórios.

    Quando uma função não existir, não
    se desespere! Sempre tem um Activex, uma ffl ou até a
    API do Windows para lhe ajudar. Olhe o exemplo que fizeram com
    a GDI+ (http://www.gotdotnet.com/codegallery/codegallery.aspx?id=0826d7a6-1dab-4a71-8e70-f2170c3c1661).
    Nada mais do que criar bibliotecas prontas para acessar a API
    do Windows que trata exclusivamente do subsistema GDI+.

    Então vamos pensar no seguinte problema: Quero saber
    se a calculadora do Windows esta em execução para
    informar ao meu usuário, por exemplo. Neste caso ao invés
    de reclamara que essa ou aquela linguagem possui esta possibilidade
    e a sua não, vamos ver o código abaixo:

    #DEFINE
    TH32CS_SNAPPROCESS  2
    #DEFINE TH32CS_SNAPTHREAD   4
    #DEFINE TH32CS_SNAPMODULE   8
    #DEFINE MAX_PATH          260
    #DEFINE PE32_SIZE  296

    DECLARE INTEGER CloseHandle IN kernel32 INTEGER hObject

    DECLARE INTEGER CreateToolhelp32Snapshot IN kernel32;
        INTEGER dwFlags, INTEGER th32ProcessID  

    DECLARE
    INTEGER Process32First IN kernel32;
        INTEGER hSnapshot, STRING @ lppe  

    DECLARE
    INTEGER Process32Next IN kernel32;
            INTEGER hSnapshot, STRING @ lppe  

    LOCAL
    hSnapshot, lcBuffer

    hSnapshot = CreateToolhelp32Snapshot (TH32CS_SNAPPROCESS,
    0)
    lcBuffer = num2dword(PE32_SIZE) + Repli(Chr(0), PE32_SIZE-4)

    IF
    Process32First (hSnapshot, @lcBuffer) = 1
        * storing process properties to the cursor
        if VerProcessExec (lcBuffer,"calc.exe")
            =messagebox("Calculadora esta rodando")
        endif

        DO WHILE .T.
            IF Process32Next (hSnapshot,
    @lcBuffer) = 1
                    if VerProcessExec (lcBuffer,"calc.exe")
                   =messagebox("Calculadora esta rodando")
                       endif
            ELSE
                EXIT
            ENDIF
        ENDDO
    ELSE
    * 87 – ERROR_INVALID_PARAMETER
    ENDIF

    = CloseHandle (hSnapshot)
    RETURN  && main

    function VerProcessExec(lcBuffer,lcExec)
        m.execname = SUBSTR(lcBuffer, 37)
        m.execname = SUBSTR(m.execname, 1, AT(Chr(0),m.execname)-1)
    RETURN upper(m.lcExec)$m.execname

    FUNCTION  num2dword (lnValue)
    #DEFINE m0       256
    #DEFINE m1     65536
    #DEFINE m2  16777216
        LOCAL b0, b1, b2, b3
        b3 = Int(lnValue/m2)
        b2 = Int((lnValue – b3*m2)/m1)
        b1 = Int((lnValue – b3*m2 – b2*m1)/m0)
        b0 = Mod(lnValue, m0)
    RETURN Chr(b0)+Chr(b1)+Chr(b2)+Chr(b3)

    Com algumas chamadas ao Kernel32 podemos criar nossa própria
    biblioteca para fazermos praticamente qualquer coisa que o Windows
    permita realizar, mesmo tendo uma linguagem orientada a dados
    como o VFP que não tem praticamente nenhuma chamada aos
    subsistemas do sistema operacional.

    Se você não conhece nada da API da Windows, faça
    uma visita em www.news2news.com e
    encontre mais de 1000 funções descritas e com fartos
    exemplos das API win32 para que você possa realizar tudo
    que sempre quis mesmo que o VFP não lhe ofereça
    o suporte nativo.

    Mãos a obra.

  • Código aberto ou proprietário

    Velocidade,
    capacidade, agilidade e rendimento são características
    que definem o desempenho de tarefas, iniciativas, trabalhos e
    projetos. Na área de tecnologia da informação,
    o exercício de medir desempenho é árduo,
    pois como atividade-meio, destinada a oferecer condições
    para que uma empresa atinja suas metas, torna-se difícil
    o cálculo dos seus resultados principais. Afinal, invariavelmente
    o foco da avaliação centra-se na atividade-fim.
    Com o surgimento dos sistemas de código aberto em contraponto
    ao software proprietário, a medição tornou-se
    uma prática ainda mais espinhosa. Por outro lado, isso
    ampliou a importância da gestão tecnológica
    dentro das organizações.

    O crescimento dos sistemas de código
    aberto é exponencial e irreversível no mundo. O
    chamado software livre é a mais significativa inovação
    tecnológica apresentada nos últimos tempos. O
    fenômeno irá impulsionar ainda mais as empresas
    desenvolvedoras de software no País, já protagonistas
    de um crescimento anual de 20%, índice significativamente
    maior comparado ao de outros segmentos de TI, como hardware e
    serviços.

    Por outro lado, o software proprietário
    chegou a um nível de maturidade muito grande. Os grandes
    fornecedores de programas no mundo são precursores do
    desenvolvimento da tecnologia da informação, ou
    melhor, da informática, como era chamado comumente todo
    e qualquer conjunto de conhecimento na área. Porém,
    nas empresas, há uma ferrenha discussão do uso
    do software proprietário e do software de código
    aberto. Para usar, copiar e redistribuir o software proprietário, é preciso
    pagar ou solicitar uma permissão ao seu fabricante. Os
    sistemas de código aberto, ao contrário, permitem
    que o usuário efetue livremente, sem ônus algum,
    modificações no programa original.

    O
    ponto nevrálgico dessa questão está na confiabilidade
    dos sistemas e redes de computadores. Hoje, este item lidera
    a preocupação — e os investimentos — das
    empresas em TI. E na implementação de softwares,
    o que mais se pergunta é sobre sua vulnerabilidade. E
    os softwares proprietários levam (ainda) ligeira vantagem
    neste aspecto. Porém, no debate da questão, é importante
    analisar que cada corporação tem a sua estratégia
    e visão de trabalho, de acordo com as suas necessidades
    e, principalmente, interesse no desenvolvimento dos negócios.

    Tais
    referências constroem o modelo de gestão tecnológica
    da organização. Porém, são itens
    de princípio, que podem ser alterados a qualquer momento.
    Aliás, a flexibilidade é uma das maiores virtudes
    da gestão de qualquer área. No caso do segmento
    de tecnologia da informação, a prática legitima
    as ações. Assim, com relação ao software
    proprietário e ao software livre, o que se observa é que
    podem coexistir nos projetos de TI das empresas. Não há mal
    nisso. Em ambos os casos, o que se deve verificar é a
    sua performance, aliada ao custo-benefício. Ou seja, preço
    e aproveitamento. E isto só se resolve com lúcido
    e equilibrado discernimento das iniciativas de TI a serem empreendidas.