Firefox 1.5 Final!

Mozilla mais uma vez dentro dos prazos… Acaba de sair o Firefox 1.5 e o site do GetFirefox, agora redirecionando para Mozilla.com, tá com um design bem bonito pra comemorar a data… Só pra dar o recado! :)

OBS.: Ele ainda não saiu em português brasileiro…

Quanto lixo!

Impressionante a quantidade de besteiras que todo programador faz… Às vezes, uma semana depois de fazer um programa ou um site, eu já sinto raiva do script que acabei de fazer e me sinto obrigado a refazê-lo. Brincando um pouco nas férias, estou refazendo vários problemas da OBI e cada vez mais percebo a quantidade de lixo que achamos nos nossos scripts. E o pior é perceber o tempo que eu levava pra fazer aqueles problemas que podiam ser resolvidos de maneira tão simples (e eu pensava que tinha uma solução muito boa)… Estou resolvendo a lista de tarefas da modalidade Programação Nível 2, mas apenas os problemas de grafos (todos eles eu já tinha resolvido, mas estou agora programando-os melhor). Confiram as besteiras que eu fiz nos primeiros deles:

Aeroporto

[enunciado]

Um problema de grafos? Não! Mas parece muito. Na verdade, se ele pedisse qualquer coisa mais do que o grau de cada vértice eu precisaria de representar usando grafos, mas a única coisa que ele quer é que eu conte a quantidade de vezes que cada número aparece na entrada.

A primeira solução deste problema, que agora já não está mais entre nós, foi feita no curso de programação básica da OBI 2004, em Campinas, quando começava a aprender grafos. Pra vocês terem uma idéia do drama, eu fiz uma busca em profundidade pra contar o número de arestas que cada vértice tem (pra medir o grau de cada vértice).

Confiram a básica solução que fiz ontem: (e que daqui a algum tempo posso vir a achar ridícula também… hehehe)

#include <stdio.h>
#define AMAX 101

int main() {
	int a, v, x, y, t[AMAX]; // t = tráfego, grau dos vértices
	int i, maior, teste=1;

	while (scanf("%d %d", &a, &v)&&a&&v) {
		maior=0;
		for (i=1; i<=a; i++) {
			t[i]=0;
		}
		for (i=0; i<v; i++) {
			scanf("%d %d", &x, &y);
			t[x]++;
			t[y]++;
			if (t[x]>maior) {
				maior=t[x];
			}
			if (t[y]>maior) {
				maior=t[y];
			}
		}
		printf("Teste %dn", teste++);
		for (i=1; i<=a; i++) {
			if (t[i]==maior) {
				printf("%d ", i);
			}
		}
		printf("bnn");
	}

	return 0;
}

Batuíra

[enunciado]

O objetivo é achar o caminho mínimo de peso de 1 a N. Uma simples busca em profundidade resolve o problema. Agora vejam a busca em profundidade que eu faria em 2004, que ainda não tirei da minha galeria de códigos: batuira.c e comparem com a que eu fiz ontem (e que ainda poderia ser melhorada):

#include <stdio.h>
#include <values.h>
#define NMAX 101

int n, marc[NMAX], g[NMAX][NMAX];
int resultado;

void buscaemprofundidade(int v, int soma) {
	int w;

	if (v==n) {
		if (soma<resultado) {
			resultado=soma;
		}
	} else {
		marc[v]=1;
		for (w=1; w<=n; w++) {
			if (g[v][w]&&!marc[w]) {
				buscaemprofundidade(w, soma+g[v][w]);
			}
		}
	}
}

int main() {
	int x, y, xy;
	int i, j, teste=1;

	while (scanf("%d", &n)&&n) {
		resultado=MAXINT;
		for (i=1; i<=n; i++) {
			marc[i]=0;
			for (j=1; j<=n; j++) {
				g[i][j]=0;
			}
		}
		while (scanf("%d %d %d", &x, &y, &xy)&&x&&y&&xy) {
			g[x][y]=xy;
			g[y][x]=xy;
		}
		buscaemprofundidade(1, 0);
		printf("Teste %dn%dnn", teste++, resultado);
	}

	return 0;
}

Dengue

[enunciado]

Esse foi com certeza meu maior susto. Foi por causa desse problema que eu resolvi escrever este artigo… Dá até vergonha de mostrar a busca em profundidade que usei para resolver o problema anteriormente. O objetivo do problema é descobrir partindo de que vértice do grafo o vértice que se encontra mais longe tem custo menor. Ou seja, é só fazer uma busca em largura com todos os vértices. Mas antigamente eu não simpatizava muito com a busca em largura, então fiz aquela besteira. E imaginem quanto tempo eu não levei pra fazer aquela joça… Bom… Pelo menos deve ter servido pra eu quebrar a cabeça naquela época! Vejam o código novo (sujeito a mudanças, é claro!):

#include <stdio.h>
#include <values.h>
#define NMAX 101

int main() {
	int w, i, j, x, y, teste=1, g[NMAX][NMAX], n, d[NMAX], fim, ini, fila[NMAX], v, a, md[NMAX], c;

	while (scanf("%d", &n)&&n) {
		for (i=1; i<=n; i++) {
			for (j=1; j<=n; j++) {
				g[i][j]=0;
			}
		}
		for (i=1; i<n; i++) {
			scanf("%d %d", &x, &y);
			g[x][y]=1;
			g[y][x]=1;
		}
		c=0;
		md[0]=MAXINT;
		for (v=1; v<=n; v++) {
			for (i=1; i<=n; i++) {
				d[i]=n;
			}
			md[v]=0;
			d[v]=0;
			ini=0;
			fim=0;
			fila[fim++]=v;
			while (ini!=fim) {
				a=fila[ini++];
				if (d[a]>md[v]) {
					md[v]=d[a];
				}
				for (w=1; w<=n; w++) {
					if (g[a][w]&&d[w]==n) {
						d[w]=d[a]+1;
						fila[fim++]=w;
					}
				}
			}
			if (md[v]<md[c]) {
				c=v;
			}
		}
		printf("Teste %dn%dnn", teste++, c);
	}

	return 0;
}

Bom… Simplificando… Se você não é programador, não seja; você vai ficar louco! :lol: Este problema que citei aqui não acontece só com esses problemas de olimpíadas mas também com vários scripts, principalmente os que vamos alterando com o tempo e adicionando novas features. Já recomecei do zero muitos sites para deixá-los decentes e muitos programas também (essa versão do aeroporto.c já é a terceira!) e não só esses de olimpíadas (o meu programa de ouvir música, em Bash, eu já fiz umas 10 vezes).

Quando eu acabar de re-resolver todos os problemas da seção de códigos lógicos eu vou publicar todos juntos. Por enquanto, vou deixar tudo do jeito que tá pra vocês apreciarem meus scripts mal-feitos. ;)


Quem costuma visitar meu blog perceberá que apareceu um ícone lá no canto inferior direito, escrito Bom Demais para o IE. A imagem, posicionada lá embaixo usando um position:fixed; (que o IE não suporta) é de uma campanha muito legal que você pode conhecer clicando no link. Participem e tenham um site “bom demais para o Internet Explorer”! :)

Compras e Blog

Hoje, no Linuxmall, comprei um pequeno livro chamado Invasão de Redes: Ataques e Defesas e foi escrito por Tiago José Pereira Nogueira. Nunca vi nada desse cara, ninguém me recomendou esse livro e não conheço ninguém que já tenha lido ou comentado alguma coisa sobre ele. É um livro que parece ser novo e me deu vontade de comprar porque sempre quis saber trabalhar com redes no C. Ele aborda tópicos interessantes, como sockets e conexões, port scanners, DDoS, entre outras coisas. Só tô explicando pra vocês não pensarem que eu comprei porque decidi virar um cracker maligno invasor de redes… :lol: Aproveitei o frete pra comprar também um novo adesivo pro laptop, um Tux grande (de 11x13cm – eu medi antes pra ver se ficava legal no laptop) que custou R$ 2,00. A compra deve chegar quinta-feira. A propósito, alguém já ouviu falar de E-Sedex? Parece ser legal… Barato e rápido! Pedi essa compra com ele pra testar. Faz tanto tempo que não compro na internet que eu fico por fora dessas novidades!

Vou aproveitar o post pra postar os códigos que eu estou fazendo pra interpretação de BBCodes e estatísticas do blog que eu, o Hélio e o Gustavo começamos a desenvolver semana passada e queremos acabar até no máximo o final de novembro (pretendemos acabar perto do dia 15/11).

Expressões Regulares

<?php
/* A parte de regex de códigos precisa do GeSHi Highlighter. Includando-o... */
include("geshi.php");

/* Essa classe serve para ser usada com "extends", ela sozinha "não é nada". */
class Regex {

    /* Função que interpreta emoticons */
    function Emoticons() {
        $origem=Array(":)", ":(", ":D", ":P", ":O", ":S", ":lol:", ":blink:");
        $destino=Array("feliz.gif", "triste.gif", "sorriso.gif", "lingua.gif", "espantado.gif", "confuso.gif", "riso.gif", "confuso.gif");
        // EM DESENVOLVIMENTO!
    }

    /* Função que interpreta BBCodes...
     * Totalmente desenvolvida por mim. (nem parece de tão linda, né?) */
    function InterpretaBBCodes() {
        /* Vamos começar pelos [codes], porque só o que tá fora deles deve ser
           interpretado depois. */

        preg_match_all("/[code language=([a-z]+)](.*)[/code]/sU", $this->texto, $matches_com_linguagens);
        preg_match_all("/[code](.*)[/code]/sU", $this->texto, $matches_sem_linguagens);

        /* - A parte dos códigos é $matches_com_linguagens[$i][2] e $matches_sem_linguages[$i][1].
               - A parte que diz em que linguagem os códigos $matches_com_linguagens[$i][2] foi escrita
              é $matches_com_linguagens[$i][1].
           - Para facilitar os códigos abaixo, vou trocar matches_com_linguagens para mcl e
           matches_sem_linguagens para msl. Só não fiz em cima pra quem tá de fora entender o que
           eu tô fazendo nessa parte do código. ;)
        */

        $mcl=$matches_com_linguagens;
        $msl=$matches_sem_linguagens;

        $con=0;
        for ($i=0; $i<sizeof ($mcl[0]); $i++) {
            $g=new GeSHi($mcl[2][$i], $mcl[1][$i], "./geshi/");
            $geshi_mcl[$i]=$g->parse_code();
            $mcl_md5[$i]=md5(time()*$con++);
            $this->texto=str_replace($mcl[0][$i], $mcl_md5[$i], $this->texto);
        }
        for ($i=0; $i</sizeof><sizeof ($msl[0]); $i++) {
            /* Aqui, vocês vão perguntar: "Por que passar no GeSHi, se não sei highlightear essa linguagem?
               A resposta é que o GeSHi não só highlighta, mas formata o código de forma que ele fique
               legível (por exemplo, troca < por &lt. */
            $g=new GeSHi($msl[1][$i], "", "./geshi/");
            $geshi_msl[$i]=$g->parse_code();
            $msl_md5[$i]=md5(time()*$con++);
            $this->texto=str_replace($msl[0][$i], $msl_md5[$i], $this->texto);
        }

        /* Beleza, agora precisamos sempre lembrar de não highlightear o que estiver entre
           E também não podemos deixar nada fora dos padrões XHTML Strict. */

        $this->texto=str_replace("&", "&", $this->texto);
        $this->texto=str_replace("< ", "<", $this->texto);
        $this->texto=str_replace(">", ">", $this->texto);
        $this->texto=str_replace(""", """, $this->texto);

        // Aqui tá o meu "nl2br" semântico! =)
        $this->texto="<p>".$this->texto."</p>";
        $this->texto=preg_replace("/\n\n\n*/", "<p>", $this->texto);
              /* </p><p></p> vazios não são semânticos. Mas estive pensando depois de fazer isso e acho que
                  algumas pessoas podem querer dar um grande espaço entre os <p>, por isso estou
                  pensando em fazer uma ER que a cada n a mais de dois n's adicione 10px ao
                  margin-bottom do último </p><p>. O que vocês acham? */
        $this->texto=preg_replace("/\n/", "<br />\n", $this->texto);
        $this->texto=preg_replace("/</p></p><p>/", " </p>\n<p>", $this->texto);

        // Formatação básica (negrito, itálico, sublinhado, cores, cabeçalhos)
        $this->texto=preg_replace("/[b](.*)[/b]/sU", "<strong>\1</strong>", $this->texto);
        $this->texto=preg_replace("/[i](.*)[/i]/sU", "<em>\1</em>", $this->texto);
        $this->texto=preg_replace("/[u](.*)[/u]/sU", "<span style="text-decoration:underline;">\1</span>", $this->texto);
        $this->texto=preg_replace("/[color=([^]]+)](.*)[/color]/sU", "<span style="color:\1;">\2</span>", $this->texto);
        $this->texto=preg_replace("/[h([1-6])](.*)[/h\1]/sU", "<h \1>\2< /h\1>n", $this->texto);

        // Citações
        $this->texto=preg_replace("/[quote](.*)[/quote]/sU", "<q>\1</q>n", $this->texto);
        $this->texto=preg_replace("/[quote=([^]]+)](.*)[/quote]/sU", "<q>\2</q>n<cite>\1</cite>", $this->texto);

        // URLs
        $this->texto=preg_replace("/([^\"/=]])(www.[^[:blank:]\"< ]+)/", "\1<a href=\"http://\2\">\2", $this->texto);
        $this->texto=preg_replace("/([^\"=]])(http://[^[:blank:]\"< ]+)/", "\1<a href=\"\2\">\2", $this->texto);

        $this->texto=preg_replace("/[url]([^\"]*)[/url]/sU", "<a href=\"\1\">\1</a>", $this->texto);
        $this->texto=preg_replace("/[url=([^[:blank:]\"]+)[[:blank:]]+title=([^]\"]+)](.*)[/url]/sU", "<a href=\"\1\" title=\"\2\">\3</a>", $this->texto);
        $this->texto=preg_replace("/[url=([^\]\"]+)](.*)[/url]/sU", "<a href=\"\1\">\2</a>", $this->texto);

        preg_match_all("/<a href=\"([^\"]+)\">/U", $this->texto, $matches);

        for ($i=0; $i<count ($matches[0]); $i++) {
            $parse=parse_url($matches[1][$i]);
            $dominio=$parse["host"];
            $this->texto=str_replace($matches[0][$i], "<a href="".$matches[1][$i]."" title="Link Externo: $dominio">", $this->texto);
        }

        // Imagens
        $this->texto=preg_replace("/[img=([^]]+)]([^\"]*)[/img]/U", "<img src=\"\2\" alt=\"\1\" />", $this->texto);
        $this->texto=preg_replace("/[img]([^\"]*)[/img]/U", "<img src=\"\1\" alt=\"Imagem: \2\" />", $this->texto);

        // Listas
        $this->texto=preg_replace("/[list](.*)[/list]/sU", "<ul>\1</ul>", $this->texto);
        $this->texto=preg_replace("/[li](.*)[/li]/sU", "<li><p>\1</p></li>", $this->texto);

        // Limpando besteiras... Alguém tem alguma idéia melhor do que esse FOR feio?
        for ($count=0; $count<10; $count++) {
            $this->texto=preg_replace("/<br /></li>/", "", $this->texto);
            $this->texto=preg_replace("/<ul><br />/", "</ul><ul>", $this->texto);
              $this->texto=preg_replace("/< (/?)li><br />/", "< \1li>",  $this->texto);
              $this->texto=preg_replace("/<q><br />/", "</q><q>", $this->texto);
              $this->texto=preg_replace("/< /q><br />/", "</q>", $this->texto);
          }

          // Emoticons
          // $this->Emoticons();

          /* Lembram que o código tinha sido transformado em md5s com o tempo, pros
             bbcodes não entrarem em ação dentro deles? Então vamos transformar de
             volta em códigos agora... */

          for ($i=0; $i<sizeof ($mcl[0]); $i++) {
              $this->texto=str_replace($mcl_md5[$i], $geshi_mcl[$i], $this->texto);
          }

          for ($i=0; $i</sizeof><sizeof ($msl[0]); $i++) {
              $this->texto=str_replace($msl_md5[$i], $geshi_msl[$i], $this->texto);
          }

          // Limpando as besteiras que não precisam ser repetidas (e coloquei depois dos codes porque
          // aqui corrijo o negócio com os <pre>s.
          $this->texto=preg_replace("/<p>[[:blank:]]*<pre>(.*)< /pre>[[:blank:]]*< /p>/sU", "<\/pre><pre>\1<\/pre>", $this->texto);
          $this->texto=preg_replace("/</p><p>[[:blank:]]*<ul>(.*)< /ul>[[:blank:]]*< /p>/sU", "</ul><ul>\1</ul>", $this->texto);
          $this->texto=preg_replace("/</p><p>[[:blank:]]*<h (.)>(.*)< /h\1>[[:blank:]]*< /p>/sU", "</h><h \1>\2</h>", $this->texto);
          $this->texto=preg_replace("/< ([^>]+)>[[:blank:]]?< /\1>/", "", $this->texto);

          // E pra finalizar, o mais mala de todos... =)
          $this->texto.="\n";
      }
  }
  ?>

Tá bem comentado e queria pedir pra quem puder, dar uma testada com ele (coloquem uns BBCodes errados e coisas que vocês acham que eu não iria prever). Aí embaixo então a parte das estatísticas, para as quais estou usando um pouco do código do Shortstat. Ela tá assim por enquanto:

Estatísticas

<?php
class Estatisticas {
    var $ip, $pais, $codigopais, $referer, $url, $dominio, $res, $useragent, $navegador, $versaonavegador, $plataforma, $unixtime;

    /* Função que descobre o IP real do visitante
     * Copiada de: www.foo.com.br
     */
    function IpReal() {
        if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "desconhecido")) {
            $ip=getenv("HTTP_CLIENT_IP");
        } else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "desconhecido")) {
            $ip=getenv("HTTP_X_FORWARDED_FOR");
        } else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "desconhecido")) {
            $ip=getenv("REMOTE_ADDR");
        } else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "desconhecido")) {
            $ip=$_SERVER['REMOTE_ADDR'];
        } else {
            $ip="desconhecido";
        }

        return $ip;
    }

    /* Função para descobrir navegador, sistema operacional, etc. com base no User Agent.
     * "SI_parseUserAgent()" do Shortstat, levemente modificada.
     */
    function ParseUserAgent($ua) {
        $plataforma="Desconhecida";
        $navegador="Desconhecido";
        $versao="";

        if (eregi("Win", $ua)) {
            $plataforma="Windows";
        } else if (eregi("Mac", $ua)) {
            $plataforma="Macintosh";
        } else if (eregi("Linux", $ua)) {
            $plataforma="Linux";
        } else if (eregi("W3C", $ua)) {
            $plataforma="W3C Validator";
            $navegador="W3C Validator";
            $versao="-";
        } else if (eregi("Googlebot", $ua)) {
            $plataforma="Googlebot";
        } else if (eregi("msnbot", $ua)) {
            $plataforma="MSNBot";
        } else if (eregi("Cynthia", $ua)) {
            $plataforma="Cynthia";
            $navegador="Cynthia";
            $versao="0";
        }

        if (eregi("Mozilla/4", $ua)&&!eregi("compatible", $ua)) {
            $navegador="Netscape";
            eregi('Mozilla/([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }
        if (eregi("Mozilla/5", $ua)||eregi("Gecko", $ua)) {
            $navegador="Mozilla";
            eregi('rv(:| )([[:digit:].]+)', $ua, $b);
            $versao=$b[2];
        }
        if (eregi("Safari", $ua)) {
            $navegador="Safari";
            $plataforma="Macintosh";
            eregi('Safari/([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }
        if (eregi("iCab", $ua)) {
            $navegador="iCab";
            eregi('iCab/([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }
        if (eregi("Firefox", $ua)) {
            $navegador="Firefox";
            eregi('Firefox/([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }
        if (eregi("Firebird", $ua)) {
            $navegador="Firebird";
            eregi('Firebird/([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }
        if (eregi("Phoenix", $ua)) {
            $navegador="Phoenix";
            eregi('Phoenix/([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }
        if (eregi("Camino", $ua)) {
            $navegador="Camino";
            eregi('Camino/([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }
        if (eregi("Chimera", $ua)) {
            $navegador="Chimera";
            eregi('Chimera/([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }
        if (eregi("Netscape", $ua)) {
            $navegador="Netscape";
            eregi('Netscape[0-9]?/([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }
        if (eregi("MSIE", $ua)) {
            $navegador="Internet Explorer";
            eregi('MSIE ([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }
        if (eregi("Opera", $ua)) {
            $navegador="Opera";
            eregi('Opera( |/)([[:digit:].]+)', $ua, $b);
            $versao=$b[2];
        }
        if (eregi("OmniWeb", $ua)) {
            $navegador="OmniWeb";
            eregi('OmniWeb/([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }
        if (eregi("Konqueror", $ua)) {
            $navegador="Konqueror";
            $plataforma="Linux";
            eregi('Konqueror/([[:digit:].]+', $ua, $b);
            $versao=$b[1];
        }
        if (eregi('Crawl', $ua) || eregi('bot', $ua) || eregi('slurp', $ua) || eregi('spider', $ua)) {
            $navegador="Crawler/Search Engine";
            $versao="-";
        }
        if (eregi('Lynx', $ua)) {
            $navegador="Lynx";
            eregi('Lynx/([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
            $plataforma="Linux";
        }
        if (eregi('Links', $ua)) {
            $navegador="Links";
            eregi('(([[:digit:].]+)', $ua, $b);
            $versao=$b[1];
        }

        $array=Array($navegador, $versao, $plataforma);
        return $array;
    }

    /* Função para determinar o país do visitante
     * "SI_determineCountry()", do Shortstat, bem modificada por mim.
     */
    function DeterminarPais($ip) {
        global $BASE;
        $ip=sprintf("%u", ip2long($ip));

        $db=new $BASE['TYPE'];
        $db->Conecta();
        $db->Query("SELECT nome, codigo FROM ".$BASE['TABELA_PAISES']." WHERE ip_from < = $ip AND ip_to >= $ip");
        $array=$db->FetchRow();

        $db->Desconecta();

        /* Agora um monte de linhas por causa da incompetência do PHP 5.0.5... Hehehe... */
        $tmp1=preg_replace("/([A-ZxC0-xDF])/e", "chr(ord('\1')+32)", $array[0]);
        $tmp2=ucwords($tmp1);
        $array[0]=trim($tmp2);

        return $array;
    }

    /* Função para "increase stats"
     * O arquivo "inc.stats.php" do Shortstat, bem modificado por mim.
     */
    function IncStats() {
        global $BASE;
        $this->ip=$this->IpReal();
        list($this->pais, $this->codigopais)=$this->DeterminarPais($this->ip);
        $this->referer=$_SERVER["HTTP_REFERER"];
        $this->url=parse_url($this->referer);
        $this->dominio=eregi_replace("^www", "", $this->url["host"]);
        $this->resource=$_SERVER["REQUEST_URI"];
        $this->useragent=$_SERVER["HTTP_USER_AGENT"];
        list($this->navegador, $this->versaonavegador, $this->plataforma)=ParseUserAgent($this->useragent);
        $this->unixtime=time();

        $db=new $BASE['TYPE'];
        $db->Conecta();
        $db->Query("INSERT INTO ".$BASE['TABELA_ESTATISTICAS']." (ip, pais, codigopais, dominio,
        referer, resource, useragent, plataforma, navegador, versao, unixtime) VALUES ('{$this->ip}',
        '{$this->pais}', '{$this->codigopais}', '{$this->dominio}', '{$this->referer}', '{$this->resource}',
        '{$this->useragent}', '{$this->plataforma}', '{$this->navegador}', '{$this->versaonavegador}',
        '{$this->unixtime}')");
        $db->Desconecta();
    }
}
?>

Bom… Esses dois códigos estão em desenvolvimento ainda, mas acho que com o tempo vão melhorando. Tem umas coisas na parte de Regex que eu queria tornar mais simples mas ainda não descobri como! :blink: Quem quiser sugerir, sinta-se a vontade.

Início no Java

Nesse final de semana, comecei a estudar Programação Orientada a Objetos. Eu nunca tinha experimentado essa maneira de programar e venho gostando bastante. :)

No início, fiz alguma coisa em C++; Depois mudei todo o sistema do meu blog para usar classes (ou “bibliotecas”, como o hlegius prefere, não sei porquê…) e agora então, por sugestão do , comecei a aprender Java.

Acho que é uma excelente maneira de me aprofundar na orientação a objetos. Desde o início da minha apostila, estou me deparando com a POO; o Java é uma linguagem completamente orientada a objetos (tanto que é sempre o exemplo quando alguém fala dela).

Pelo pouco que programei até agora (comecei hoje), percebi quatro vantagens legais que o C não tinha:

  1. Declaração de variáveis em qualquer lugar do documento. O C++, o PHP e várias outras linguagens permitem isso também…
  2. Multi-plataforma. Linux, Windows, Mac, Solaris… O mesmo código roda em tudo! :) C também roda em tudo, mas não exatamente da mesma maneira como o Java
  3. Desenvolvimento para web via applets.
  4. Parece muito fácil criar interfaces gráficas. Não sei se é mesmo, mas parece.

Bom… Não entendi direito o negócio de plataforma Java, pra ser sincero… Mas ainda tô iniciando aí nesse mundo do Java e da POO. :)

E então, para finalizar fica um código de um exercício que eu fiz; o primeiro da primeira apostila (que inclusive eu já concluí a leitura):

Calcular a soma e a média de vários números, e ver o maior e o menor

import javax.swing.JOptionPane;

/* Eu não precisava de array para esse programa, só usei porque
 * estou aprendendo Java então preciso me acostumar com arrays... */

class Exercicio {
import javax.swing.JOptionPane;

/* Eu não precisava de array para esse programa, só usei porque
 * estou aprendendo Java então preciso me acostumar com arrays... */

class Exercicio {
        public static void main(String args[]) {
                int n;
                String string;

                JOptionPane.showMessageDialog(null, "Olá. Esse programa serve pra calcular a soma e a média entre vários números, além de definir o maior e o menor deles.");
                JOptionPane.showMessageDialog(null, "Restrições:nn1. Só funciona com números entre -1.000.000 e 1.000.000.n2. Só funciona (a entrada e a saída) com números inteiros.");
                string=JOptionPane.showInputDialog("Você quer calcular a média entre quantos termos?");
                n=Integer.parseInt(string);

                int array[] = new int[n];
                int i, m, soma=0, maior=-1000000, menor=1000000;

                for (i=0; i<n; i++) {
                        m=i+1;
                        string=JOptionPane.showInputDialog("Digite o "+m+"o. número:");
                        array[i]=Integer.parseInt(string);
                        soma+=array[i];
                        if (array[i]>maior) {
                                maior=array[i];
                        }
                        if (array[i]<menor) {
                                menor=array[i];
                        }
                }

                int media=soma/n;

                JOptionPane.showMessageDialog(null, "A soma de todos os números é "+soma+".");
                JOptionPane.showMessageDialog(null, "A média de todos os números é "+media+".");
                JOptionPane.showMessageDialog(null, "O maior dos números é "+maior+".");
                JOptionPane.showMessageDialog(null, "O menor dos números é "+menor+".");
        }
}

No mais, nada de novo. Só pra registrar a data de meu início no Java. :D

Mudanças no Site e Código do Blog

Atenção: os códigos desta postagem, além de inúteis, estão com muitos erros de sintaxe. Foram convertidos entre várias plataformas de blog e perderam muita coisa. Estão guardados aqui apenas para registro.

Ultimamente fiz várias alterações no site. Refiz quase que todas as páginas e deixei tudo um pouco mais leve e mais fácil para mudar depois. :D Depois de conhecer a POO, me viciei nela no final de semana e converti meu site inteiro para classes. E agora, que seu script tá um pouco melhor organizado, vou colocar aqui para quem quiser copiar, usar alguma idéia, saber como eu estou indo em POO, ver as besteiras que eu faço enquanto programo, etc. :lol: resolvi disponibilizar todo o código de meu blog aqui.

Já que meu blog tem alguns bugs (known bugs de pouca importância, como o caso de se alguém escreve CHARESPC no meio de um comentário ele deve criar um &;), peço somente que ninguém destrua-o sabendo disso. Se alguém descobrir algum bug, pode me enviar um e-mail que ficarei bastante grato. :)

Já que não passei a sessão de administração para POO não vou publicá-la aqui, mas depois de resolver alguns bugzinhos pretendo disponibilizar o código completo, inclusive com um arquivo de instalação que cria as tabelas no banco de dados, para todos poderem usar um sisteminha de blog simples e prático (só que acho que vai ser algo mais voltado a programadores, porque tem vantagens como o uso do GeSHi, e desvantagens como eu publicar todos os posts escrevendo em HTML – isso mesmo, até os & que eu escrevo são & que são & *e um loop infinito pela frente). Hmmm, aliás, quem quiser me ajudar a fazer parte desse projeto para tornar o meu blog um software livre, sinta-se livre para me mandar um e-mail também. :p

Então, uma última observação é que eu substituí todos os <code (note a ausência do > ) por tag code e todos os por tag /code, porque senão minhas expressões regulares do código dariam bug (quer saber por que? Então leia os códigos!)

Funções e classes “includadas” em todos os arquivos {#funcoeseclasses}

<?php
session_start();

// Syntax Highlight - GeSHi
if (!class_exists(GeSHi)) {
	include("geshi.php");
}

// Objeto de conexão do MySql
class MySql {
	var $host="servidor";
	var $usuario="usuario";
	var $senha="senha";
	var $db="bancodedados";
	var $conexao;

	function conecta() {
		$this->conexao=mysql_connect($this->host, $this->usuario, $this->senha);
		mysql_select_db($this->db);
	}

	function desconecta() {
		mysql_close($this->conexao);
	}
}

// Classe com as funções de expressões regulares
class Regex {
	function Replace($o, $d, $t, $codes=0) {
		for ($i=0; $i<sizeof($o); $i++) {
			$o[$i]=str_replace('(', '(', $o[$i]);
			$o[$i]=str_replace(')', ')', $o[$i]);
			$t=eregi_replace($o[$i], $d[$i], $t);
		}
		if ($codes==1) {
			$t="tag /code".$t."tag code";
		} else if ($codes==2) {
			$t.="tag code";
		} else if ($codes==3) {
			$t="tag /code".$t;
		}
		return $t;
	}

	function Emoticons() {
		$o[0]=":)";
		$d[0]="feliz";
		$o[1]=":(";
		$d[1]="triste";
		$o[2]=":o";
		$d[2]="bocaaberta";
		$o[3]=":p";
		$d[3]="lingua";
		$o[4]=":angry:";
		$d[4]="raiva";
		$o[5]=":s";
		$d[5]="confuso";
		$o[6]=":blink:";
		$d[6]="inacreditavel";
		$o[7]=";)";
		$d[7]="piscando";
		$o[8]=":lol:";
		$d[8]="rindo";
		$o[9]=":d";
		$d[9]="sorriso";
		$o[10]=":unsure:";
		$d[10]="semgraca";

		for ($i=0; $i<sizeof($d); $i++) {
			$d[$i]="<img src="/emoticon/".$d[$i].".gif" alt="".$o[$i]."" />";
		}

		if (!ereg("tag code", $texto)) {
			$this->texto=$this->Replace($o, $d, $this->texto);
		} else {
			preg_match_all("/</code>(.+)tag code/sU", $this->texto, $mat1);
			for ($i=0; $i<sizeof($mat1[1]); $i++) {
				$this->texto=str_replace($mat1[1][$i], $this->Replace($o, $d, $mat1[1][$i]), $this->texto);
			}
			preg_match("/^(.+)tag code/sU", $this->texto, $mat2);
			$texto=str_replace($mat2[1], $this->Replace($o, $d, $mat2[1]), $this->texto);
			$rev=strrev($this->texto); //Tenho medo do PHP5.0.5
			preg_match("/^(.+)>edoc/</sU", $rev, $mat3); //Nossa, que código louco!
			$rev=strrev($mat3[1]); //Repito... Tenho medo do PHP5.0.5
			$this->texto=str_replace($rev, $this->Replace($o, $d, $rev), $this->texto); //Agora fuck PHP5.0.5!
		}
	}

	function GeshiHighlight($codigo, $linguagem) {
		$geshi=new GeSHi($codigo, $linguagem, "./geshi/");
		return $geshi->parse_code();
	}

	function Codigos() {
		preg_match_all("/tag code class=\"(.*)\">(.*)</code>/sU",
			$this->texto,
			$matches);
		for ($i=0; $i<sizeof($matches[1]); $i++) {
			$g=$this->GeshiHighlight($matches[2][$i], $matches[1][$i]);
			if (eregi("MSIE", $_SERVER["HTTP_USER_AGENT"])) {
				$g=ereg_replace("<pre>", "<pre class="alturamaxima">", $g);
			}
			$this->texto=str_replace($matches[0][$i],
				$g,
				$this->texto);
		}
	}

	function QuebraLinha() {
		$this->texto=nl2br($this->texto);
	}
}

// Objeto "Artigo"
class Artigo extends Regex {
	var $id;
	var $data;
	var $permalink;
	var $titulo;
	var $texto;
	var $comentarios;

	function Artigo($identificacao) {
		$this->id=$identificacao;

		$mysql=new MySql();
		$mysql->conecta();

		$query_post=mysql_query("SELECT data, permalink, titulo, texto FROM artigos WHERE id='{$this->id}'");
		$post=mysql_fetch_row($query_post);
		$this->data=date("d/m/Y", $post[0]);
		$this->permalink=$post[1];
		$this->titulo=$post[2];
		$this->texto=$post[3];

		$query_comentarios=mysql_query("SELECT count(id) FROM comentario WHERE idpost='{$this->id}'");
		$comentarios=mysql_fetch_row($query_comentarios);
		$this->comentarios=$comentarios[0];

		$mysql->desconecta();
	}

	function AppendGoogleAds($ads) {
		$this->texto.="nn".$ads;
	}

	function Mostra() {
		echo "<h2><a href=\"/post/{$this-?PHPSESSID=9ec34c96b02b3755051aa682d1e02001>permalink}\">{$this->titulo}</a></h2>\n";
		echo $this->texto."\n";
		echo "<h5>{$this->data} ";
    echo "<a href=\"/post/{$this-?PHPSESSID=9ec34c96b02b3755051aa682d1e02001>permalink}\" class=\"permalink\">permalink</a> ";
    echo "<a href=\"/post/{$this-?PHPSESSID=9ec34c96b02b3755051aa682d1e02001>permalink}#comentarios\" class=\"comentarios\">";
    echo "{$this->comentarios} comentário(s)</a></h5>\n";
	}

	function MostraComentarios() {
		if ($_POST["comenta"]&&(!$_SESSION["comentario"]||time()-30>$_SESSION["comentario"])) {
			$_SESSION["comentario"]=time();
			EscreveComentario($_POST["nome"], $_POST["email"], $_POST["texto"], $this->id);
		}
		$comentarios=new Comentarios($this->id);
		$comentarios->Mostra();
	}
}

// Objeto Artigos (serve para pegar vários artigos sem eu precisar fazer nada nas outras páginas)
class Artigos {
	var $id;
	var $titulo;
	var $texto;
	var $permalink;
	var $data;
	var $comentarios;

	function Artigos($n=20, $start=0, $emoticons=0, $codigos=0, $mostrar=0, $comentarios=0) {
		$mysql=new MySql();
		$mysql->conecta();
		$query=mysql_query("SELECT id FROM artigos ORDER BY data DESC, id DESC LIMIT $start,$n");
		$mysql->desconecta();
		for ($i=0; $array=mysql_fetch_array($query); $i++) {
			$artigo=new Artigo($array["id"]);
			if ($emoticons) {
				$artigo->Emoticons();
			}
			if ($codigos) {
				$artigo->Codigos();
			}
			if ($mostrar) {
				$artigo->Mostra();
			}
			if ($comentarios) {
				$artigo->MostraComentarios();
			}
			$this->id[$i]=$array["id"];
			$this->titulo[$i]=$artigo->titulo;
			$this->texto[$i]=$artigo->texto;
			$this->permalink[$i]=$artigo->permalink;
			$this->comentarios[$i]=$artigo->comentarios;
			$this->data[$i]=$artigo->data;
		}
	}
}

// Objeto Comentário
class Comentario extends Regex {
	var $id;
	var $data;
	var $nome;
	var $email;
	var $ip;
	var $useragent;
	var $texto;
	var $numero;

	function Comentario($identificacao, $numero) {
		$this->id=$identificacao;
		$this->numero=$numero;

		$mysql=new MySql();
		$mysql->conecta();

		$query=mysql_query("SELECT data, nome, email, ip, useragent, texto FROM comentario WHERE id='{$this->id}'");
		$comentario=mysql_fetch_row($query);

		$this->data=date("d/m/Y", $comentario[0]);
		$this->nome=$comentario[1];
		if ($_SESSION["tiagomadeira"]) {
			$this->email="</small> <span style=\"font-size:10px;\"><br />";
			if ($comentario[2]) $this->email.="<strong>E-mail:</strong> ".$comentario[2]."<br />n";
			if ($comentario[3]) $this->ip="<strong>IP:</strong> ".$comentario[3]."<br />n";
			if ($comentario[4]) $this->useragent="<strong>User Agent:</strong> ".$comentario[4];
			$this->useragent.="</span>";
		} else {
			$this->email="</small>";
		}
		$this->texto=$comentario[5];

		$mysql->desconecta();
	}

	function CharEspc($pos) {
		if ($pos==1) {
			$this->texto=preg_replace("/&([^;]+);/sU", "CHARESPC\1/CHARESPC", $this->texto);
		} else if ($pos==2) {
			$this->texto=preg_replace("/CHARESPC(.+)/CHARESPC/sU", "&\1;", $this->texto);
		}
	}

	function Mostra() {
		echo "<div class=\"comentario\" id=\"com{$this->id}\">\n";
    echo "\t <h4><a href=\"?PHPSESSID=9ec34c96b02b3755051aa682d1e02001#com{$this->id}\">#{$this->numero}</a> | ";
    echo "{$this->nome} ";
    echo "<small>{$this->data}{$this->email}{$this->ip}{$this->useragent}</h4>\n";
    echo "<p>{$this->texto}</p>";
    echo "</div>\n";
  }
}

// Objeto Comentários
class Comentarios {
  var $idpost;
  var $ids;
  var $tamanho;

  function Comentarios($idpost) {
    $this->idpost=$idpost;

    $mysql=new MySql();
    $mysql->conecta();

    $query=mysql_query("SELECT id FROM comentario WHERE idpost='{$this->idpost}' ORDER BY data ASC, id ASC");
    for ($i=1; $array=mysql_fetch_array($query); $i++) {
      $this->ids[$i]=$array["id"];
    }

    $this->tamanho=$i;
    $mysql->desconecta();
  }

  function Mostra() {
    echo "<h3 id="comentarios">Comentários</h3>\n";
    for ($i=1; $i<$this->tamanho; $i++) {
      $comentario=new Comentario($this->ids[$i], $i);
      $comentario->CharEspc(1);
      $comentario->Emoticons();
      $comentario->CharEspc(2);
      $comentario->QuebraLinha();
      $comentario->Mostra();
    }

    if ($this->tamanho <= 1) {
      echo "<p>Nenhum comentário cadastrado.</p>\n";
    }

    FormularioComentario($this->idpost);
  }
}

// Função para descobrir IP do visitante
function PegaIP() {
  if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "desconhecido")) {
    $ip=getenv("HTTP_CLIENT_IP");
  } else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "desconhecido")) {
    $ip=getenv("HTTP_X_FORWARDED_FOR");
  } else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "desconhecido")) {
    $ip=getenv("REMOTE_ADDR");
  } else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "desconhecido")) {
    $ip=$_SERVER['REMOTE_ADDR'];
  } else {
    $ip="desconhecido";
  }

  return($ip);
}

// Função que escreve o formulário para envio de comentário
function FormularioComentario($idpost) {
  $mysql=new MySql();
  $mysql->conecta();
  $query=mysql_query("SELECT permalink FROM artigos WHERE id='$idpost'");
  $row=mysql_fetch_row($query);
  $permalink=$row[0];
  $mysql->desconecta();
?>

<h3>
  Escreva um comentário
</h3>

<?php
}

// Função que cadastra um comentário
function EscreveComentario($nome, $email, $texto, $idpost) {
$ip=PegaIP();
$useragent=$_SERVER["HTTP_USER_AGENT"];
$nome=purifica($nome);
$email=purifica($email);
$texto=purifica($texto);
$data=time();
$mysql=new MySql();
$mysql->conecta();
  mysql_query("INSERT INTO comentario (id, idpost, nome, email, texto, data, ip, useragent) VALUES
    ('', '$idpost', '$nome', '$email', '$texto', '$data', '$ip', '$useragent')") or die(mysql_error());
  $mysql->desconecta();
  $email=($email)?$email:"contato@tiagomadeira.net";
  $mensagem="No post de id $idpost, o $nome ($email) comentou em ".date("d/m/Y", $time)." dizendo:";
  $mensagem.="nn";
  $mensagem.="$texto";
  mail("contato@tiagomadeira.net", "[tiagomadeira.net] Novo Comentário!", "$mensagem", "From: $nome <$email>");
}

// Função que cria escreve o título das seções
function titulo($titulo) {
  $tit="$titulo [tiagomadeira.net]";
  echo "n";
}

// Função para purificar os comentários depois do envio
function purifica($texto) {
  $t=ereg_replace("&", "&", $texto);
  $t=ereg_replace("%", "%", $t);
  $t=ereg_replace("<", "<", $t);
  $t=ereg_replace(">", ">", $t);
  $t=ereg_replace("[", "[", $t);
  $t=ereg_replace("]", "]", $t);
  $t=ereg_replace(""", """, $t);
  return $t;
}

// Função para editar artigos
function pra_textarea($texto) {
  $texto=ereg_replace("&", "&", $texto);
  $texto=ereg_replace("<", "<", $texto);
  $texto=ereg_replace(">", ">", $texto);
  $texto=ereg_replace(""", """, $texto);
  return $texto;
}
?>

E os arquivos que usam essas funções e classes…

/artigos (ou /blog)

<?php
  $artigosporpagina=10; //Artigos Por Página
  $p=($_GET["pg"])?$_GET["pg"]:1; //Página Atual

  $mysql=new MySql();
  $mysql->conecta();
  $query=mysql_query("SELECT count(id) FROM artigos");
  $row=mysql_fetch_row($query);
  $np=ceil($row[0]/$artigosporpagina);
  $mysql->desconecta();

  $paginacao="";
  for ($i=1; $i<=$np; $i++) {
    $paginacao.="<a href="/artigos/$i"";
    if ($i==$p) $paginacao.=" style="font-weight:bold; color:#c00;"";
    $paginacao.=">$i</a> ";
  }
  $paginacao="\n\n<p style=\"text-align:center;\"><span style=\"color:#aaa; font-size:11px;\">";
  $paginacao.="Ir para página:</span> $paginacao</p>\n\n";

  echo $paginacao;

  $artigos=new Artigos($artigosporpagina, ($p-1)*$artigosporpagina);
  echo " <ul>\n";
  for ($i=0; $i<count($artigos->id); $i++) {
      echo "<li><a href=\"{$artigos->permalink[$i]}\">{$artigos->titulo[$i]}</a><br />";
      echo "<small>{$artigos->data[$i]} ";
      echo "<a class=\"comentarios\" href=\"/post/{$artigos->permalink[$i]}#comentarios\">{$artigos->comentarios[$i]} comentário(s)</a>";
      if ($_SESSION["tiagomadeira"]) {
        echo " <a href="/admin-edita&id={$artigos->id[$i]}">[editar]</a>";
        echo " <a href="/admin-exclui&id={$artigos->id[$i]}">[excluir]</a>";
      }
      echo "</small></li>\n";
  }
  echo "</ul>n";
  echo $paginacao;
?>

/ (ou /ultimos)

<?php
	$artigos=new Artigos(5, 0, 1, 1, 1);
?>

Para finalizar… .htaccess

RewriteEngine On

#Diretórios
RewriteRule ^link/?$ http://tableless.tiagomadeira.net
RewriteRule ^post/?$ http://tableless.tiagomadeira.net/blog
RewriteRule ^script/?$ http://tableless.tiagomadeira.net/scripts
RewriteRule ^downloadscript/?$ http://tableless.tiagomadeira.net/scripts

#Blog: A grande excessão
RewriteRule ^blog/([0-9]+)$ http://tableless.tiagomadeira.net/index.php?l=blog&pg=$1
RewriteRule ^/link/blog/([0-9]+)$ http://tableless.tiagomadeira.net/index.php?l=blog&pg=$1
RewriteRule ^artigos/([0-9]+)$ http://tableless.tiagomadeira.net/index.php?l=blog&pg=$1
RewriteRule ^/link/artigos/([0-9]+)$ http://tableless.tiagomadeira.net/index.php?l=blog&pg=$1

#Links
RewriteRule ^link/(.+)$ http://tableless.tiagomadeira.net/index.php?l=$1
RewriteRule ^([^/.]+)$ http://tableless.tiagomadeira.net/index.php?l=$1

#Posts
RewriteRule ^post/([0-9]+)$ http://tableless.tiagomadeira.net/index.php?l=artigo&id=$1
RewriteRule ^post/(.+)$ http://tableless.tiagomadeira.net/index.php?l=artigo&permalink=$1

#Scripts
RewriteRule ^script/(.+)$ http://tableless.tiagomadeira.net/index.php?l=script&script=$1
RewriteRule ^downloadscript/(.+)$ http://tableless.tiagomadeira.net/downloadscript.php?script=$1

#Feeds
RewriteRule ^feed.rss$ http://tableless.tiagomadeira.net/rss.php
RewriteRule ^rss.xml$ http://tableless.tiagomadeira.net/rss.php
RewriteRule ^index.rss$ http://tableless.tiagomadeira.net/rss.php
RewriteRule ^sitemap.xml$ http://tableless.tiagomadeira.net/sitemap.php
© 2005–2020 Tiago Madeira