Mostrando uma agenda do Google Calendar no seu site

Escrito em PHP. Pode ser usado no tema do seu WordPress. Requer CURL. Faz cache do calendário para não ter que baixá-lo sempre que alguém entra no seu site. Desenvolvido para um site que vai sair nos próximos dias. Use, modifique e distribua como quiser. (Não me responsabilizo por qualquer problema. Fiz pra um caso específico. A checagem de erros é meio porca.)

<?php
date_default_timezone_set('America/Sao_Paulo');
$events = Array();
$dom = new DOMDocument();

$file = "cached_calendar.xml";

$last = -1;
if (file_exists($file)) {
    $last = filemtime($file);
}
// Mude 3600 para o tempo (em segundos) que você quiser que o cache expire
if (time() - $last > 3600) {
    $fp = fopen($file, "w+");
    if (!$fp) {
        die();
    }
    // Substitua o e-mail do calendário do Google CodeJam pelo e-mail do seu calendário (público)
    $ch = curl_init("https://www.google.com/calendar/feeds/" .
      "google.com_jqv7qt9iifsaj94cuknckrabd8%40group.calendar.google.com/public/full");
    curl_setopt($ch, CURLOPT_TIMEOUT, 50);
    curl_setopt($ch, CURLOPT_FILE, $fp);
    curl_exec($ch);
    curl_close($ch);
    fclose($fp);
}

$dom->load($file);
$feed = $dom->getElementsByTagName("feed");
$entries = $feed->item(0)->getElementsByTagName("entry");
foreach ($entries as $entry) {
    $children = $entry->getElementsByTagName("*");
    $day = "";
    $start = "";
    $end = "";
    foreach ($children as $child) {
        switch ($child->tagName) {
        case "title":
            $title = $child->nodeValue;
            break;
        case "gd:when":
            if ($child->hasAttribute("startTime")) {
                $st = strtotime($child->getAttribute("startTime"));
                $time_to_sort = $st;
                $day = date_i18n("l, d/M", $st);
                $start = date("H:i", $st);
            }
            if ($child->hasAttribute("endTime")) {
                $et = strtotime($child->getAttribute("endTime"));
                $end = date("H:i", $et);
            }
            break;
        }
    }
    if ($title != "" && $day != "") {
        $events[] = Array(
            "time_to_sort" => $time_to_sort,
            "day" => $day,
            "start" => $start,
            "end" => $end,
            "title" => $title
        );
    }
}
function cmp($a, $b) {
    $a = $a["time_to_sort"];
    $b = $b["time_to_sort"];
    if ($a == $b) {
        return strcmp($a["title"], $b["title"]);
    }
    return ($a < $b) ? -1 : 1;
}
usort($events, "cmp");

$n = count($events);
if ($n > 0) {
    $lastDay = "";
    for ($i = 0; $i < $n; $i++) {
        $day = $events[$i]['day'];
        $title = $events[$i]['title'];
        $start = $events[$i]['start'];
        $end = $events[$i]['end'];
        if ($lastDay != $day) {
            if ($i != 0) {
                echo "</ul>\n\n";
            }
            echo "<h3 class="day"><span>$day</span></h3>\n";
            echo "<ul>\n";
          }
          echo "\t<li>\n";
            if ($start != "") {
                // Você pode modificar aqui para mostrar o horário de término ($end).
                echo "tt<span class="time">{$start}</span>\n";
            }
            echo "\t\t<strong>{$title}</strong>\n";
            echo "\t</li>\n";
          $lastDay = $day;
      }
      echo "</ul>\n";
} else {
    echo "<p>Nenhum evento cadastrado.</p>\n";
}
?>

Como recuperar a inicialização do Linux depois de instalar Windows

Esse é um problema super comum que já resolvi para dezenas de pessoas e resolvi escrever aqui pra não ficar tendo que repetir a resolução toda vez que alguém me perguntar.

O caso é o seguinte: você tem Linux numa das suas partições e por algum motivo estranho instala Windows (ou reinstala) na outra. O Windows, como todo sistema operacional para idiotas, simplesmente limpa sua MBR (master boot record do HD) sem lhe perguntar nada e com isso deleta seu gerenciador de boots (neste post estarei tratando o Grub e o Lilo).

Aí você se vê triste, desiludido e em muitos casos resolve reinstalar o Linux só pra recuperar o boot. Péssimo, não? Mas não se preocupe: seus problemas acabaram.

Tudo o que você precisará para recuperar sua MBR (com Grub ou Lilo) é:

  1. Um livecd (não precisa ser um daqueles pesadões, um disco 1 do Slackware ou Gentoo Minimal resolve) com a mesma arquitetura do seu Linux. Se você não tem, sugiro o Gentoo Minimal porque é leve: o download você faz aqui. Se você não sabe o que é arquitetura, você provavelmente usa x86.
  2. Saber em que partição se encontra seu Linux (tipo: /dev/hda1, /dev/sda1, ou algo do gênero) e em que HD ele se encontra (tipo: /dev/hda, /dev/sda… é só tirar o número da partição)

Se você não sabe em que partição/hd está seu Linux, é fácil descobrir através do comando fdisk -l

Boote o livecd (considerarei que você sabe fazer isso, do contrário não teria conseguido instalar o Windows) e abra um terminal se seu livecd for gráfico (é aquela telinha preta, também pode ser chamado de Console).

Agora o que vamos fazer é montar a partição root do seu Linux (e considerarei que /boot não está numa partição separada, se estiver monte ela também), entrar nela e reinstalar o Grub ou o Lilo.

Se o seu terminal terminar com um caractere $ (cifrão), digite “sudo su” para virar root. Agora pode digitar o que segue:

# mkdir linux
# mount /dev/hda1 linux
# mount -o bind /dev linux/dev
# mount -t proc none linux/proc
# chroot linux /bin/bash
# source /etc/profile
# cat /proc/mounts > /etc/mtab

Não se esqueça de substituir /dev/hda1 pela partição do seu Linux.

Agora, se você usa Grub (se não, provavelmente esse comando não dará problema, então se você estiver na dúvida pode chutar esse):

# grub-install --recheck /dev/hda

(substituindo /dev/hda pelo device do seu hd)

Ou se você usa Lilo:

# lilo

E pronto! Limpando a sujeira…

# exit
# umount linux/proc
# umount linux/dev
# umount linux

E pode rebootar pro seu velho Linux.

Se você não tinha Windows antes, o Windows não vai por mágica aparecer nas suas opções de boot. Então, no seu velho Linux, é só editar o arquivo /boot/grub/menu.lst (pra quem usa Grub) ou /etc/lilo.conf (pra quem usa Lilo) e colocar linhas para bootar o Windows, respectivamente:

title Windows
rootnoverify (hd0,1)
makeactive
chainloader +1

e

other=/dev/hda2
label=Windows

(assumindo que seu Windows está em /dev/hda2)

É importante que você note que o Grub inicia suas contagens a partir do 0. hda1 é (hd0,0), hda2 é (hd0,1), hdb1 é (hd1,0), hdc2 é (hd2,1). Deu pra entender? Letra antes da vírgula (a = 0, b = 1, c = 2, …) e número depois da vírgula (1 = 0, 2 = 1, 3 = 2, …)

Para editar um arquivo como root, escreva “su” para virar root e use “vim”, ou, se você não sabe fazer isso, sua distribuição provavelmente permite que você digite algo como: “sudo gedit arquivo” ou “sudo kwrite arquivo”.

Se você usa Lilo, é necessário que depois de salvar o arquivo você entre no terminal como root e digite:

# lilo

… para salvar suas alterações na MBR.

É isso. Reinicie seu computador e divirta-se com seu gerenciador de boots funcionando novamente. Qualquer dúvida, escrevam comentários.

HOWTO: Como usar Pandora Radio no Brasil

O projeto Pandora é uma rádio on-line que funciona como um catálogo bem categorizado de milhares de CDs e é capaz de reproduzir músicas parecidas com o tipo que você diz para ele que gosta. Ficou confuso? É assim: eu entro lá e escrevo que gosto de Chico Buarque. Aí ele me diz: vamos tocar uma música do Chico que tem suas características principais como canto em português, violão leve, etc. Responda se você gostou ou não e baseado nessa escolha tocaremos outro estilo ou continuaríamos no mesmo.

É uma idéia muito legal porque no fim você ouve apenas o que gosta, mas também descobre novas músicas (porque ele não fica repetindo artista, álbum, música, mas só as características da música ou do artista que você selecionou a princípio).

Fazia tempo que eu não usava o Pandora porque num esforço comunitário de minha família, digitalizamos algumas centenas de CDs criando uma biblioteca de 35 gb em MP3. Porém, meu desktop (Durion 1.1) que era meu servidor de música (MPD) recentemente morreu (a placa-mãe deu pau) e, cansado de ouvir as poucas músicas que tinha aqui no laptop, resolvi ver como andava o Pandora.

Porém, fui surpreendido por uma mensagem dizendo que por causa de copyright brasileiros não podem mais usar o Pandora. Isso é um problema que eles dizem estar conversando com as autoridades para resolver, mas por hora não podem aceitar IPs brasileiros, o que me levou a buscar uma solução.

A primeira coisa que pensei foi procurar um servidor de proxy nos Estados Unidos. É fácil se você entrar no Public Proxy Servers, mas a velocidade deles realmente não me agrada, ainda mais pra ouvir uma rádio on-line. Então, pesquisei um pouco e depois de algum tempo encontrei a solução: SSH tunneling (túneis de SSH?)

Eu uso SSH todo dia e nunca tinha me dado conta que ele tem uma opção super interessante que é numa dada porta criar um tunelamento que pode ser usado como servidor SOCKS (proxy). Aí você pensa: mas qual a vantagem? De qualquer jeito você terá que usar um servidor proxy e ficar com a internet mais lenta. Sim, é verdade, mas o meu servidor na Dreamhost é sem dúvidas muito mais rápido que um proxy público e eu tenho certeza que minhas informações ficam seguras. Aliás, é por segurança que a maioria das pessoas usa SSH tunneling (ex.: pessoas com laptop numa rede wireless pública)

Vamos ao prático:

$ ssh -C -D 666 -N user@host

E configure seu navegador para usar Socks (eu usei V5, mas a V4 deve funcionar também) para o endereço: 127.0.0.1 (isso mesmo, não é o host que você colocou no SSH, é a sua máquina, porque ela que criou o servidor) na porta que você especificou com o parâmetro -D (nesse caso 666)

As opções do SSH que eu utilizei no exemplo são:

  • -C: comprime entrada e saída. Nos exemplos que eu peguei vinha, acredito que seja pras transferências serem mais rápidas.
  • -D [bind:]port: porta (e um endereço opcional) pro servidor rodar
  • -N: não executa nenhum comando (ie não abre um shell)

Esta dica funciona em sistemas operacionais que tem SSH (Linux, FreeBSD e provavelmente qualquer outro Unix-like). Para usá-la no Windows, você deve usar o PuTTy.

Windows é mais fácil?

Na minha opinião, a facilidade de uma ação depende da praticidade de execução da mesma (ou seja, do tempo que ela demora pra ser executada). Quando eu converso com algum leigo sobre Linux, depois de eu convencê-lo com vários argumentos que o Linux não só tem muito mais recursos como ainda tem uma filosofia muito mais bonita, ele sempre diz: “Mas Linux é muito difícil!”

Eu não acho que Linux seja difícil, eu acho que é diferente do que elas estão acostumadas. E as pessoas precisam ter mais disposição pra testar e aprender o novo! É claro que no início elas vão ter dificuldade, mas o Linux não é nenhum bicho de sete cabeças!

Porém, o foco desse pequeno post não é questionar a dificuldade por esse aspecto, mas questionar a praticidade de uso dos dois sistemas.

Vou propôr um problema básico: baixei 500 fotos de uma viagem (com uma qualidade foda, tipo 2048×1536) para o meu computador. Elas estão muito grandes e quero diminuí-las para publicá-las no meu site. As imagens para a web não precisam ser muito grandes e nem ter uma qualidade muito alta. Eu não quero que elas tenham aquele nome feio DSC_….JPG que elas têm e quero que os arquivos tenham nomes em minúsculas do tipo viagem-N.jpg. Isso não é nenhuma realidade distante, é algo que eu sempre preciso fazer…

No meu Linux (com Funções ZZ e ImageMagick), eu simplesmente escreveria:

$ zzarrumanome *
$ zznomefoto -p viagem- *.jpg
$ mkdir fotosnovas
$ for i in *.jpg; do
> convert -geometry 640 -quality 75 $i fotosnovas/$i
> done

Como fazer isso no Windows? Se alguém conhece uma maneira, me ensine nos comentários. Eu gostaria muito de saber pra ensinar aos meus amigos que sempre precisam disso! :-)

[update] E vejam o que o MeioBit acabou de postar… eu ainda acho a minha maneira muito mais fácil! [/update]

udev e suas regras maravilhosas

Participei nos dias 8 e 9 do IV Encontro Nacional Linuxchix Brasil em Florianópolis. O evento teve umas palestras interessantes, entre as quais destaco as do pessoal do FreeBSD, a do Luiz Fernando Capitulino sobre o desenvolvimento do Kernel, a do Hélio Castro sobre interfaces gráficas 3D, mas em especial a do Piter PUNK sobre o udev (talvez porque eu sou um usuário Slackware =). E é sobre o udev que eu resolvi falar nesse artigo…


Tenho até vergonha de dizer que até semana passada eu não tinha percebido que o hotplug não estava mais sendo inicializado no meu Slackware… Só depois da palestra que aprendi que o Kernel 2.6 acaba com a necessidade do hotplug substituindo por um novo e poderoso aplicativo chamado udev. Isso é uma mudança e tanto, que traz alguns prós e contras (na verdade, eu só vi prós).

O que é o udev?

Bom… Segundo a Wikipedia, udev is the device manager for the Linux 2.6 kernel series. Its primary function is managing device nodes in /dev. It is the successor of devfs and hotplug, which means that it handles the /dev directory and all user space actions when adding/removing devices, including firmware load.

Como funciona o udev

Na inicialização do sistema, o udev vê no /sys que dispositivos foram encontrados pelo Kernel e adiciona os dispositivos ao /dev (por enquanto, vou fingir que ele só adiciona os dispositivos ao /dev).

Depois, seu daemon fica rodando para adicionar novos dispositivos assim que eles aparecerem.

É bem mais rápido que no hotplug e parece funcionar bem.

E onde está a mágica?

O udev possue um diretório de regras (/etc/udev/rules.d) onde adicionamos arquivos de texto com uma sintaxe super fácil para dizer o que queremos fazer com cada dispositivo que é adicionado ao sistema.

E o que queremos fazer com cada dispositivo que é adicionado ao sistema?

Hmmm… Isso depende muito da sua necessidade, mas deixe-me citar algumas possibilidades das regras do udev:

  • Dar nome aos dispositivos – Pra que uma pasta /dev cheia de nomes difíceis que você não entende? Com o udev, você pode chamar seu sda1 de pendrive ou o seu hdc de cdrom.
  • Dar nomes diferentes para dispositivos iguais – Hoje em dia vivemos pluggando pendrives, máquinas digitais, MP3 players, etc. em nossas placas USB. Com o udev, podemos fazer com que a nossa máquina da Canon chame-se /dev/canon, a nossa máquina da Sony chame-se /dev/sony, o pendrive da mamãe chame-se /dev/mamae e o nosso MP3 Player chame-se /dev/mp3player.
  • Adicionar links simbólicos aos dispositivos – Podemos fazer nosso CD-ROM ter vários links como cdrom, dvd, cdrw, cdwriter
  • Mudar permissões dos dispositivos – Podemos fazer com que o pendrive da mamãe possa, logo que for pluggado em qualquer porta USB, ser acessado por ela (e somente por ela).
  • Executar comandos quando ocorrem alterações nos dispositivos – Sempre que a mamãe colocar o seu pendrive numa porta USB podemos montá-lo para ela e já abrir o dispositivo no Konqueror e quando ela pluggar a sua máquina digital da Canon podemos mudar suas permissões, linká-la para /dev/camera e abrir o digiKam.
  • … entre provavelmente muitas outras coisas que eu não me lembro ou não sei fazer (eu só conheço o udev há quatro dias!)

Claro que o udev pode ser útil para servidores também, para trocar hardware ou reiniciar o computador com segurança (ex.: você pode dizer que o HD principal seja sempre /dev/principal e assim mesmo que ele passe a ser o seu Second Slave ele funciona), mas estou focando mais o uso doméstico. A “mamãe” é um usuário leigo que não precisa saber montar dispositivos ou qual o nome do programa que baixa as fotos da máquina. Ela simplesmente plugga a sua máquina e o digiKam abre.

Legal… E como é que eu faço essas regras?

A sintaxe dos arquivos em /etc/udev/rules.d é muito simples. Você simplesmente separa por vírgulas as condições que você quer para que as ações que você quer fazer e as ações.

A máquina fotográfica da mamãe

ACTION=="add", BUS=="usb", SYSFS{product}=="Canon Digital Camera",
GROUP="camera", MODE="0660", SYMLINK+="camera", RUN:="/bin/su mamae -c
'/usr/bin/abredigikam.sh'"

Aqui em casa, usei um “abredigikam.sh” assim:

#!/bin/bash

export DISPLAY=":0"
/opt/kde/bin/digikam
Sinais do exemplo
  • Os dois iguais (==) são para expressar condição, como no C (e em um monte de linguagens derivadas dele).
  • O “=” atribui
  • O “+=” atribui “mais uma coisa” (append)
  • O “:=” atribui uma coisa como constante (ou seja, neste caso eu ou os scripts de regras da minha distro não conseguem mais mudar o valor do “RUN”).
Variáveis do exemplo
  • ACTION: A ação que está sendo feita com o dispositivo (neste caso é a adição dele – add)
  • BUS: Barramento. Neste caso, a USB.
  • SYSFS: Variáveis específicas deste dispositivo (depois vou mostrar como encontramos elas)
  • GROUP: Grupo em que o dispositivo está.
  • MODE: Permissões do dispositivo.
  • SYMLINK: Links simbólicos para o dispositivo.
  • RUN: Comando Shell para executar.

Não conheço todas as variáveis, mas para saber mais você pode consultar o Writing udev rules (o objetivo desse post não é entrar em detalhes).

udevmonitor

O udevmonitor é um aplicativo que imprime os eventos recebidos pelo Kernel e o evento que o udev manda depois do proessamento de regras em tempo real. Veja o que acontece, por exemplo, quando pluggo uma máquina digital na minha porta USB:

UEVENT[1158086870.385094] add@/devices/pci0000:00/0000:00:02.0/usb1/1-1
UEVENT[1158086870.388950] add@/devices/pci0000:00/0000:00:02.0/usb1/1-1/1-1:1.0
UEVENT[1158086870.389571] add@/class/usb_device/usbdev1.3
UDEV  [1158086870.390983] add@/devices/pci0000:00/0000:00:02.0/usb1/1-1
UDEV  [1158086870.404378] add@/devices/pci0000:00/0000:00:02.0/usb1/1-1/1-1:1.0

É interessante para acompanharmos os dispositivos que são encontrados pelo udev. Veja agora o udevmonitor quando eu despluggo a minha máquina:

UEVENT[1158089965.438657] remove@/devices/pci0000:00/0000:00:02.0/usb1/1-1/1-1:1.0
UEVENT[1158089965.438765] remove@/class/usb_device/usbdev1.3
UEVENT[1158089965.438794] remove@/devices/pci0000:00/0000:00:02.0/usb1/1-1
UDEV  [1158089965.440899] remove@/devices/pci0000:00/0000:00:02.0/usb1/1-1/1-1:1.0
UDEV  [1158089965.443341] remove@/class/usb_device/usbdev1.3
UDEV  [1158089965.444795] remove@/devices/pci0000:00/0000:00:02.0/usb1/1-1

udevinfo

O udevinfo imprime informações sobre um dispositivo. Para descobrir que o SYSFS{product} da minha máquina era Canon Digital Camera foi este comando que eu utilizei, da seguinte maneira:

<strong># udevinfo -q all -n usbdev1.4</strong>
P: /class/usb_device/usbdev1.4
N: usbdev1.4
S: bus/usb/1/4

(descobri que ela estava na usbdev1.4 usando o udevmonitor)

Aí agora sabendo o path eu descobri todo o resto: (a saída é grande, use a barra de rolagem)

# udevinfo -a -p /class/usb_device/usbdev1.4
Udevinfo starts with the device specified by the devpath and then
walks up the chain of parent devices. It prints for every device
found, all possible attributes in the udev rules key format.
A rule to match, can be composed by the attributes of the device
and the attributes from one single parent device.

  looking at device '/class/usb_device/usbdev1.4':
    KERNEL=="usbdev1.4"
    SUBSYSTEM=="usb_device"
    DRIVER==""
    SYSFS{dev}=="189:3"

  looking at parent device '/devices/pci0000:00/0000:00:02.0/usb1/1-1':
    ID=="1-1"
    BUS=="usb"
    DRIVER=="usb"
    SYSFS{configuration}==""
    SYSFS{product}=="Canon Digital Camera"
    SYSFS{manufacturer}=="Canon Inc."
    SYSFS{maxchild}=="0"
    SYSFS{version}==" 1.10"
    SYSFS{devnum}=="4"
    SYSFS{speed}=="12"
    SYSFS{bMaxPacketSize0}=="8"
    SYSFS{bNumConfigurations}=="1"
    SYSFS{bDeviceProtocol}=="00"
    SYSFS{bDeviceSubClass}=="00"
    SYSFS{bDeviceClass}=="00"
    SYSFS{bcdDevice}=="0001"
    SYSFS{idProduct}=="30f9"
    SYSFS{idVendor}=="04a9"
    SYSFS{bMaxPower}=="  2mA"
    SYSFS{bmAttributes}=="c0"
    SYSFS{bConfigurationValue}=="1"
    SYSFS{bNumInterfaces}==" 1"

  looking at parent device '/devices/pci0000:00/0000:00:02.0/usb1':
    ID=="usb1"
    BUS=="usb"
    DRIVER=="usb"
    SYSFS{configuration}==""
    SYSFS{serial}=="0000:00:02.0"
    SYSFS{product}=="OHCI Host Controller"
    SYSFS{manufacturer}=="Linux 2.6.17.11 ohci_hcd"
    SYSFS{maxchild}=="4"
    SYSFS{version}==" 1.10"
    SYSFS{devnum}=="1"
    SYSFS{speed}=="12"
    SYSFS{bMaxPacketSize0}=="64"
    SYSFS{bNumConfigurations}=="1"
    SYSFS{bDeviceProtocol}=="00"
    SYSFS{bDeviceSubClass}=="00"
    SYSFS{bDeviceClass}=="09"
    SYSFS{bcdDevice}=="0206"
    SYSFS{idProduct}=="0000"
    SYSFS{idVendor}=="0000"
    SYSFS{bMaxPower}=="  0mA"
    SYSFS{bmAttributes}=="e0"
    SYSFS{bConfigurationValue}=="1"
    SYSFS{bNumInterfaces}==" 1"

  looking at parent device '/devices/pci0000:00/0000:00:02.0':
    ID=="0000:00:02.0"
    BUS=="pci"
    DRIVER=="ohci_hcd"
    SYSFS{modalias}=="pci:v000010B9d00005237sv0000103Csd00000024bc0Csc03i10"
    SYSFS{local_cpus}=="1"
    SYSFS{irq}=="10"
    SYSFS{class}=="0x0c0310"
    SYSFS{subsystem_device}=="0x0024"
    SYSFS{subsystem_vendor}=="0x103c"
    SYSFS{device}=="0x5237"
    SYSFS{vendor}=="0x10b9"

  looking at parent device '/devices/pci0000:00':
    ID=="pci0000:00"
    BUS==""
    DRIVER==""

Os contras

Hmmm… Na verdade, pelo que eu me lembro da palestra, o udev só tem um contra. Ele vai detectando os dispositivos e jogando-os no /dev na ordem em que ele vai encontrando-os. Então, às vezes a minha placa de rede SiS pode ser detectada como eth0 e a Realtek como eth1 e no outro dia o contrário. Mas contornar isso é muito simples, usando aquelas regras (e inclusive podemos dar os nomes /dev/placa-sis e /dev/placa-realtek para nossas placas). =)

Encontrou um erro?

Eu ainda tô conhecendo o udev (como eu disse, conheci ele nesse final de semana), então meu texto pode ter alguma falha ou pode estar faltando alguma informação. Por favor, comente se encontrar algum erro ou quiser sugerir algo legal… =)

Para mais informações…

$ man udev

… e a página do udev

© 2005–2020 Tiago Madeira