helio.loureiro.eng.br
  • Home
  • Unix
  • Linux
  • Blog
  • Python
  • Programação
  • Tudo
  • Suécia
  1. You are here:  
  2. Home

Os artigos mais lidos de 2025

  • Configurando o grafana alloy pra monitorar VMs
  • Configurando traefik com ssh
  • Acessos de robôs nos logs web
  • Configurando o teclado Keychron C3 no Linux
  • Parâmetros de compilação pra Go!

Home

Países considerados os mais felizes do mundo escondem problemas graves - a identidade

Details
Written by: Helio Loureiro
Category: Suécia
Published: December 23, 2021
Hits: 5189

Caso não tenha lido os artigos anteriores:

  • Minha experiência de quase COVID na Suécia
  • Países considerados os mais felizes do mundo escondem problemas graves
  • Países considerados os mais felizes do mundo escondem problemas graves - as crianças

Como bom brasileiros, nascidos na burocracia, estamos acostumados a ter vários números pra diferentes finalidades.  CPF pra coisas relacionadas com imposto, RG pra identidade, certificado de reservista, cartão eleitoral, etc.  E cada um com um número qualquer que temos em geral de memorizar.

Na Suécia sua vida toda é ligada ao que é chamado de "personnummer", ou "personal number" em inglês, ou número pessoal na boa e velha língua tupiniquim.  Ele é composto de <ano em que nasceu><mês em que nasceu><dia em que nasceu>-<4 dígitos aleatórios>.  Algo como YYYYMMDD-ABCD.  Simples assim.

O ano de nascimento pode ser usado tanto o formato YY como YYYY.   Nos documentos aparecem no formato YY, mas quando recebe seu número, via carta, ele vem no formato do ano completo com 4 dígitos, YYYY.

E com esse número baseado no seu aniversário você faz tudo: vota, tira carteira de motorista, faz o imposto de renda, vai ao médico, contrata serviços pelo telefone, etc.

De posse do número, você pode tirar a sua carteira de identidade de estrangeiro residente.

A moçoila bonita da foto nasceu em 12 de junho de 1970 de acordo com seu "personnummer".   Existe um número gigantesco no topo à esquerda, o "kortnummer", que é "número do cartão", mas esse não é usado pra nada.

O mesmo formato aplica-se pra identidade de quem é cidadão sueco.

A diferença dessas identidades é que a primeira é emitida pelo skatteverket, órgão responsável por cobrar os impostos e também de registro civil, e o segundo, pela polícia.   O cartão emitido pelo skatteverket tem mais a aparência e formato de um cartão de crédito comum, enquanto que a carteira emitida pela polícia é um papel plastificado num plástico rígido.

Existe também a carteira de motorista, emitida pelo trafiksverket, órgão responsável controle e regulamentação de tráfego.

A carteria de motorista, körkort em sueco (kör - dirigir, kort - cartão), tem a data de nascimento no campo 3 e o número pessoal no campo 5, que mostra a mesma data em formato invertido e mais os 4 últimos dígitos aleatórios/verificadores (parece que os 2 últimos são os verificadores).  Aqui dentro da Suécia a carteira de motorista serve como identidade.   Tanto que só ando com ela na carteira.

Nas viagens que fiz aqui pela europa, a maioria dos aeroportos aceitou só a carteira de motorista pra embarcar.  Exceção foi o aeroporto internacional de Lisboa, que exigiu meu passaporte.

O ponto interessante aqui é que seu nome não diz muita coisa.  Quem o define é seu número pessoal.  Então qualquer pessoa pode ir ao skatteverket, onde está o registro civil, e mudar seu nome quando quiser, quantas vezes quiser e pro que quiser.  Parece simples, não?  E realmente é.

Claro que alguns podem argumentar que um sistema simples desse pode levar a um maior monitoramento de sua vida e atividades privadas.   Eu diria que sim.  Mas acho que benefício de ter um só número significativo pra tudo na sua vida compensa isso.  A menos que você seja um despachante.

Refatorando meu script de bloqueio de youtube no openwrt

Details
Written by: Helio Loureiro
Category: Shell Scripts
Published: December 19, 2021
Hits: 4314

Filho aborrecente é... aborrecente.  E infelizmente tenho de tempos em tempos de usar a artimanha de bloquear o YouTube pra conseguir sua atenção e fazer as suas tarefas.

Hoje eu estava revendo o script que criei em bloqueando Youtube no OpenWRT, criado em 2018.  Dei uma melhorada no código e fiz o cáculo do horário de uma forma melhor.

Precisei carregar os módulos "bc" e "iptables-mod-filter" no openwrt pra funcionar como desejado.


#! /bin/sh
# save it into /usr/lib/scripts/firewall.sh
# and add into scheduled tasks as
# */5 * * * * /usr/lib/scripts/firewall.sh timetable

NOW=$(date +"%H:%M")
TIMETABLE="07:55,10:00 12:00,18:00 20:30,22:00"

status_file=/tmp/firewall_status

blocked_pattern="youtubei.googleapis.com"
blocked_pattern="$blocked_pattern googlevideo.com"
blocked_pattern="$blocked_pattern ytimg-edge-static.l.google.com"
blocked_pattern="$blocked_pattern i.ytimg.com"
blocked_pattern="$blocked_pattern youtube-ui.l.google.com"
blocked_pattern="$blocked_pattern www.youtube.com"
blocked_pattern="$blocked_pattern googleapis.l.google.com"
blocked_pattern="$blocked_pattern youtubei.googleapis.com"
blocked_pattern="$blocked_pattern video-stats.l.google.com"
blocked_pattern="$blocked_pattern ytimg-edge-static.l.google.com"

enable_firewall() {
    echo "Enabling firewall"
    for chain in INPUT FORWARD OUTPUT
        do
        count=1
        for proto in tcp udp
            do
                for blocked in $blocked_pattern
                    do
                    echo iptables -I $chain $count -p $proto -m string --algo bm --string "$blocked" -j DROP
                    iptables -I $chain $count -p $proto -m string --algo bm --string "$blocked" -j DROP
                    count=`expr $count + 1`
                done
        done
        echo iptables -I $chain $count -p udp --sport 443 -j DROP
        iptables -I $chain $count -p udp --sport 443 -j DROP
        count=`expr $count + 1`
        echo iptables -I $chain $count -p udp --dport 443 -j DROP
        iptables -I $chain $count -p udp --dport 443 -j DROP
        count=`expr $count + 1`
    done
    echo -n "enabled" > $status_file
}

disable_firewall() {
    echo "Disabling firewall"
    for chain in INPUT FORWARD OUTPUT
        do
        for proto in tcp udp
            do
                for blocked in $blocked_pattern
                    do
                    echo iptables -D $chain -p $proto -m string --algo bm --string "$blocked" -j DROP
                    iptables -D $chain -p $proto -m string --algo bm --string "$blocked" -j DROP
                done
        done
        echo iptables -D $chain -p udp --sport 443 -j DROP
        iptables -D $chain -p udp --sport 443 -j DROP
        echo iptables -D $chain -p udp --dport 443 -j DROP
        iptables -D $chain -p udp --dport 443 -j DROP
    done
    echo -n "disabled" > $status_file
}

_get_time_as_integer() {
  time=$1

  hour=$(echo $time | cut -d: -f 1)
  minute=$(echo $time | cut -d: -f 2)

  echo "$hour * 100 + $minute" | bc
}

_get_start_time(){
    # expected format: 07:00,10:00
    time_str=$1

    time_start=$(echo $time_str | cut -d, -f 1)
    _get_time_as_integer $time_start
}

_get_stop_time() {
    #expected format: 07:00,10:00
    time_str=$1

    time_stop=$(echo $time_str | cut -d, -f 2)
    _get_time_as_integer $time_stop
}

get_timetable() {

do_activate=0
for value in $TIMETABLE
    do
    start=$(_get_start_time $value)
    stop=$(_get_stop_time $value)
    cur_time=$(_get_time_as_integer $NOW)
    if [ $start -lt $cur_time ]; then
        if [ $cur_time -lt $stop ]; then
           do_activate=1
        fi
    fi
done

cur_status=$(cat $status_file)
if [ $do_activate ]; then
    if [ "$cur_status" = "enabled" ]; then
        echo "firewall already activated"
    else
       echo "activating firewall"
       enable_firewall
    fi
else
    if [ "$cur_status" = "enabled" ]; then
       echo "deactivating firewall"
       disable_firewall
    else
        echo "firewall already deactivated"
    fi
fi
}

case $1 in
    start) enable_firewall
           exit 0;;
    stop) disable_firewall
          exit 0;;
    timetable) get_timetable
               exit 0;;
    status) echo "firewall rules are $(cat $status_file)";;
    *) echo "Use: $0 [start|stop|timetable|status]"
       exit 0
esac

exit 0

Agora os horário de bloqueio ficam na variável TIMETABLE e no format "<horário início HH:MM>,<horário fim HH:MM>".  O firewall permite um direto "start" e "stop" pra ativar, assim como um "status".  Crie alguma funções com o "_" no início, pra seguir um pouco o padrão do python de funções internas/privadas.

Seu funcionamento agora ficou muito bom e fácil, pra desespero dos aborrecentes.

root@OpenWrt:/usr/lib/scripts# ls
firewall.sh
root@OpenWrt:/usr/lib/scripts# ./firewall.sh status
firewall rules are disabled
root@OpenWrt:/usr/lib/scripts# ./firewall.sh timetable
activating firewall
Enabling firewall
iptables -I INPUT 1 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I INPUT 2 -p tcp -m string --algo bm --string googlevideo.com -j DROP
iptables -I INPUT 3 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I INPUT 4 -p tcp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I INPUT 5 -p tcp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I INPUT 6 -p tcp -m string --algo bm --string www.youtube.com -j DROP
iptables -I INPUT 7 -p tcp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I INPUT 8 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I INPUT 9 -p tcp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I INPUT 10 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I INPUT 11 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I INPUT 12 -p udp -m string --algo bm --string googlevideo.com -j DROP
iptables -I INPUT 13 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I INPUT 14 -p udp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I INPUT 15 -p udp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I INPUT 16 -p udp -m string --algo bm --string www.youtube.com -j DROP
iptables -I INPUT 17 -p udp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I INPUT 18 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I INPUT 19 -p udp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I INPUT 20 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I INPUT 21 -p udp --sport 443 -j DROP
iptables -I INPUT 22 -p udp --dport 443 -j DROP
iptables -I FORWARD 1 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I FORWARD 2 -p tcp -m string --algo bm --string googlevideo.com -j DROP
iptables -I FORWARD 3 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I FORWARD 4 -p tcp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I FORWARD 5 -p tcp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I FORWARD 6 -p tcp -m string --algo bm --string www.youtube.com -j DROP
iptables -I FORWARD 7 -p tcp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I FORWARD 8 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I FORWARD 9 -p tcp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I FORWARD 10 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I FORWARD 11 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I FORWARD 12 -p udp -m string --algo bm --string googlevideo.com -j DROP
iptables -I FORWARD 13 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I FORWARD 14 -p udp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I FORWARD 15 -p udp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I FORWARD 16 -p udp -m string --algo bm --string www.youtube.com -j DROP
iptables -I FORWARD 17 -p udp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I FORWARD 18 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I FORWARD 19 -p udp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I FORWARD 20 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I FORWARD 21 -p udp --sport 443 -j DROP
iptables -I FORWARD 22 -p udp --dport 443 -j DROP
iptables -I OUTPUT 1 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I OUTPUT 2 -p tcp -m string --algo bm --string googlevideo.com -j DROP
iptables -I OUTPUT 3 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I OUTPUT 4 -p tcp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I OUTPUT 5 -p tcp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I OUTPUT 6 -p tcp -m string --algo bm --string www.youtube.com -j DROP
iptables -I OUTPUT 7 -p tcp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I OUTPUT 8 -p tcp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I OUTPUT 9 -p tcp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I OUTPUT 10 -p tcp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I OUTPUT 11 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I OUTPUT 12 -p udp -m string --algo bm --string googlevideo.com -j DROP
iptables -I OUTPUT 13 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I OUTPUT 14 -p udp -m string --algo bm --string i.ytimg.com -j DROP
iptables -I OUTPUT 15 -p udp -m string --algo bm --string youtube-ui.l.google.com -j DROP
iptables -I OUTPUT 16 -p udp -m string --algo bm --string www.youtube.com -j DROP
iptables -I OUTPUT 17 -p udp -m string --algo bm --string googleapis.l.google.com -j DROP
iptables -I OUTPUT 18 -p udp -m string --algo bm --string youtubei.googleapis.com -j DROP
iptables -I OUTPUT 19 -p udp -m string --algo bm --string video-stats.l.google.com -j DROP
iptables -I OUTPUT 20 -p udp -m string --algo bm --string ytimg-edge-static.l.google.com -j DROP
iptables -I OUTPUT 21 -p udp --sport 443 -j DROP
iptables -I OUTPUT 22 -p udp --dport 443 -j DROP
root@OpenWrt:/usr/lib/scripts# ./firewall.sh timetable
firewall already activated
root@OpenWrt:/usr/lib/scripts# ./firewall.sh status
firewall rules are enabled
root@OpenWrt:/usr/lib/scripts# date
Sun Dec 19 13:51:32 CET 2021

Boa diversão.  Ou não caso seja o aborrescente lendo esse artigo pra descobrir o porquê seu YouTube parou de funcionar.

No roadmap: incluir TikTok e Instagram.

UPDATE: eu por fim criei um repositório no github pra ficar mais fácil a manutenção: https://github.com/helioloureiro/opewrt-youtube-blocker

Modificando um livecd de Ubuntu

Details
Written by: Helio Loureiro
Category: Linux
Published: December 11, 2021
Hits: 5215

Não é sempre que preciso fazer dessas coisas, mas recentemente precisei mexer num disco de livecd do Ubuntu que estava em formato iso pra alterar algumas coisa.

Então aqui fica receita de como fazer isso (dependendo do que deseja fazer, claro).

Primeiro eu tenho dois diretórios que uso pra montagem dos filesystems.  Os /cdrom e /mnt.  Como já uso desse forma faz anos, não sei se são criados por padrão no Ubuntu ou outro sistemas.  Então se for copiar o que descrevo aqui, tenha certeza que esses diretórios existem.  Outro ponto importante é que rodo todos os comandos como root.

Então o começo de tudo é montar a imagem do Ubuntu no diretório desejado.

root@goosfraba /# mount -t iso9660 -o loop ubuntu-20.04.03-desktop-amd64.iso /cdrom

Esse conteúdo precisa ser copiado  pra um diretório temporário.

root@goosfraba /# mkdir /tmp/temp-cdrom
root@goosfraba /# cd /tmp/temp-cdrom
root@goosfraba /t/temp-cdrom# tar cvf - -C /cdrom . | tar xvf -

Existe o arquivo casper/filesystem.squashfs que é o filesystem do livecd.  Você pode montar esse disco com o seguinte comando (e aqui entra o /mnt que comentei antes):

root@goosfraba /t/temp-cdrom# mount -t squashfs -o loop /tmp/temp-cdrom/casper/filesystem.squashfs /mnt

mas esse disco é apenas read-only.  Pra modificar é preciso usar a ferramenta unsquashfs que faz parte do pacote squashfs-tools.

root@goosfraba /t/temp-cdrom# mkdir /tmp/squashfs
root@goosfraba /t/temp-cdrom# cd /tmp/squashfs
root@goosfraba /t/squashfs# unsquashfs /tmp/temp-cdrom/casper/filesystem.squashfs
Parallel unsquashfs: Using 8 processors
185020 inodes (205968 blocks) to write
[=================================================================================================================================================================/] 205968/205968 100%
created 155722 files
created 19319 directories
created 29184 symlinks
created 8 devices
created 0 fifos

root@goosfraba /t/squashfs# ls squashfs-root/
bin@  boot/  dev/  etc/  home/  lib@  lib32@  lib64@  libx32@  media/  mnt/  opt/  proc/  root/  run/  sbin@  snap/  srv/  sys/  tmp/  usr/  var/

Daí sim fazer as modificações desejadas.

Ao terminar é preciso gerar a imagem no formato squashfs novamente, agora usando o mksquashfs.  Prepare-se pra ir fazer um café ou assistir um filme pois o processo demora bastante nesse passo.

root@goosfraba /t/squashfs# mksquashfs squashfs-root /tmp/temp-cdrom/casper/filesystem.squashfs -b 1024k -comp xz -Xbcj x86 -e boot
Parallel mksquashfs: Using 8 processors
Creating 4.0 filesystem on /tmp/temp-cdrom/casper/filesystem.squashfs, block size 1048576. [=================================================================================================================================================================/] 149629/149629 100%

Exportable Squashfs 4.0 filesystem, xz compressed, data block size 1048576
        compressed data, compressed metadata, compressed fragments,
        compressed xattrs, compressed ids
        duplicates are removed
Filesystem size 1695376.64 Kbytes (1655.64 Mbytes)
        32.81% of uncompressed filesystem size (5167137.40 Kbytes)
Inode table size 1550743 bytes (1514.40 Kbytes)
        20.75% of uncompressed inode table size (7473067 bytes)
Directory table size 1819524 bytes (1776.88 Kbytes)
        36.53% of uncompressed directory table size (4981005 bytes)
Xattr table size 98 bytes (0.10 Kbytes)
        81.67% of uncompressed xattr table size (120 bytes)
Number of duplicate files found 18577
Number of inodes 204220
Number of files 155715
Number of fragments 2275
Number of symbolic links  29180
Number of device nodes 8
Number of fifo nodes 0
Number of socket nodes 0
Number of directories 19317
Number of ids (unique uids + gids) 37
Number of uids 15
        root (0)
        ntp (126)
        dnsmasq (112)
        saned (119)
        speech-dispatcher (114)
        systemd-timesync (100)
        _apt (105)
        rtkit (118)
        messagebus (106)
        man (6)
        postfix (125)
        whoopsie (109)
        sshd (121)
        sddm (122)
        syslog (104)
Number of gids 28
        root (0)
        dip (30)
        shadow (42)
        lpadmin (113)
        rtkit (126)
        mysql (131)
        nogroup (65534)
        lp (7)
        audio (29)
        systemd-timesync (102)
        utmp (43)
        tty (5)
        geoclue (105)
        _ssh (118)
        input (106)
        mail (8)
        staff (50)
        avahi (120)
        man (12)
        pulse-access (125)
        whoopsie (116)
        munin (130)
        saned (127)
        pulse (124)
        uuidd (111)
        systemd-journal (101)
        adm (4)
        messagebus (110)

E o último passo é gerar o disco bootável.  Pra isso eu usei o genisoimage:

root@goosfraba /tmp# genisoimage -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -r -J -o /tmp/ubuntu-20.04.03-modificado-desktop-amd64.iso /tmp/temp-cdrom

Com isso a image iso ubuntu-20.04.03-modificado-desktop-amd64.iso é gerada.

Shell das trincheiras no Tchelinux

Details
Written by: Helio Loureiro
Category: Shell Scripts
Published: November 26, 2021
Hits: 5464

Eu estava aguardando o release oficial dessa palestra, o que aconteceu no dia 25.

Fiz uma palestra sobre programação em shell script abordando Bourne shell e resolvendo o mesmo problema que apresentei na rápida introdução ao Python na BSD Day 2021, em python, e na Latinoware 2021 - Go das trincheiras, em Go.  Dessa vez use o shell script e resolvi o mesmo problema.

 

O fim do picamera no raspberrypi

Details
Written by: Helio Loureiro
Category: Python
Published: November 20, 2021
Hits: 3095

Terminada minha maratona pessoal de participações em conferências e eventos em geral, eu decidi dedicar algum tempo pra atualizar meus sistemas.

Meu desktop passou de Ubuntu 20.04 pra 21.10.  Decidi simplesmente largar o LTS e abraçar os releases intermediários.  Tive alguns problemas com o snapd, que deu uns crashes de kernel, mas no fim tudo deu certo.  Uma boa experiência de ambiente desktop com KDE Plasma mais recente.

No servidor eu atualizei pro último Debian estável.  Eu sempre espero um pouco pra fazer isso, até sair a correção .1 do release, e foi o que fiz no final.  Mas um dos problemas que tive foram meus scripts em python.  Muitos deles foram feitos há mais de 10 anos e estavam rodando felizes com python 2.7.  O upgrade pra Debian bullseye acabou com essa alegria.   Apenas python3 restou e muita coisa parou de funcionar.  Posso dizer que até agora não encontrei tudo que quebrou após o upgrade, mas devagar estou corrigindo.

Então aproveitando o embalo eu decidi também fazer o upgrade do raspberrypi.  Mesmo sendo raspbian, é Debian.  E passei pro bullseye.  Assim como o servidor, o upgrade em si foi bem tranquilo.  Super suave.

Então percebi que meu as fotos pararam de funcionar.

tl;dr: basicamente o antigo suporte ao picamera deixou de existir.  Foi trocado pela libcamera, que não tem suporte em python ainda.

https://github.com/waveform80/picamera/issues/697

O que é possível fazer agora?  Aliás o que eu fiz pra contornar isso? Bom... não ficou bonito, mas funciona.  Chamei um dos programas que vem com o libcamera e salva fotos em jpeg usando subprocess.


class LibCameraInterface:
    def __init__(self, sleep_time=30): None

    def get_image(self, destination):
        debug("LibCameraInterface.get_image()")
        import subprocess
        width, height = IMGSIZE
        command = f"/usr/bin/libcamera-jpeg --width={width} --height={height} -o {destination}"
        subprocess.call(command.split())

Eu aproveitei e dei uma boa refatorada no código.   Ficou mais simples e pronto pra trocar.   Criei duas classes, LibCameraInterface e CameraInterface.  A ideia é voltar ao CameraInterface uma vez que tenha algum tipo de suporte em python.  Por enquanto nem pygame funciona mais.

O resultado é quase o mesmo.  Quase.  Pelo libcamera as imagens ficaram mais escura durante a noite.

O antes:

O depois:

Ambas bem escuras.  A segunda eu mudei um pouco a posição da câmera, mas mesmo pegando a iluminação dos prédios fica bem escura.   E não achei ainda um jeito de melhorar isso.

Talvez um upgrade pra próxima versão.

UPDATE:

Eu tinha esquecido de postar o link do programa no github.  Aqui está ele.

https://github.com/helioloureiro/snapshot-twitter/blob/master/weather-twitter.py

Update 2022-12-09: fui revisitar o artigo e percebi que não tinha colocado o link pro bug no github.  Então adicionei.

Resgatando a chave pública de um perfil no Jenkins

Details
Written by: Helio Loureiro
Category: Linux
Published: November 09, 2021
Hits: 4286

Pode parecer meio estranho, mas foi isso mesmo que precisei fazer: pegar a chave pública de ssh de um perfil que estava no jenkins pra configurar o acesso num repositório Gitlab.

Mas o Jenkins, sabiamente, não guarda ou mostra essas credenciais pra você.  Então precisei recorrer a meios não muito convencionais pra fazer isso.

Primeiro fooi pegar a chave privada que ele tinha armazenado.  Pra isso encontrei uma receita de bolo, escrita em Groovy.

https://scriptcrunch.com/groovy-script-retrieve-jenkins-credentials/


import jenkins.*
import jenkins.model.* 
import hudson.*
import hudson.model.*
def jenkinsCredentials = com.cloudbees.plugins.credentials.CredentialsProvider.lookupCredentials(
        com.cloudbees.plugins.credentials.Credentials.class,
        Jenkins.instance,
        null,
        null
);
for (creds in jenkinsCredentials) {
    // descomente essa parte abaixo se precisar de mais detalhes
    //println(jenkinsCredentials.id)
    println(creds.username))
    if(creds.id == "2671e11a-4831-fa3f-0d58-7b331318c04d"){
    	println(creds.privateKey)
    }
}

E pra rodar junto ao Jenkins, na área de scripts.  Se não sabia ainda, é possível rodar script pela interface web atráves da url que tem do Jenkins mais o final "/script".

No laço "if" onde olho se o creds.id bate com um número gigante, esse é o identificador que você vê como ID nas credenciais.

Esse foi o resultado:


user1
user2
user3
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAyONzf1Ti1Dv8jI68/oyGJ2Gf6CNkN64ncZAVB5QnR+0NbyzN
G9U6uFqKUoSuuYblqANJNGR3PKCVhCJCB6Ge7azPK10eYEHFyYXGuIwi9Rb3MsjN
Cof57NzenIUcErm0Cuxk34xEXdR5UFm8GI0q3MEuBSwopQfAnfGa5L+QxGt/+YuY
ei/n/V0QsgYuZb9RVF2NbTrNLk09vBQ7SVwyDzKBaaGFkO0uh6fvCz/gq8L+f9cL
Z/twZNy1/Z13VSe2Agd/1ErLBqlTrxabPCFPMWm4YiAAwIUqhwaI6GU7IRLo/HWo
9eqfvYUWh6FyBKRf7bdSdWfWSSTNxgwPCfJavQIDAQABAoIBADjjaG6znDSb9C3d
shmns8ntNHppo1S9RcA8HCh0RRdyQu6r0j3CiYlxYmBx4IT7dYe5vn5OwRFzLEQp
62b71uTZniVajmKV3avu7VKPpMqhQUmpYZ9M2HLCLWxHqaaH3juFrB8+OpITvHML
pl+RgoTXU+/1DGGHq31O0R1cPmPQyRDhaxVpzsYwbCcIYGJ1hjz2g+098LwtIr5W
5i2Z6JUpE6GyXlVZAM1f9tsYWgGGEBqbH4frUjH9Ao1F7dKARDHsiwcjbreywBx1
aVk8AsTP31vqdOJgUJC9JcM/cf2GLUQxg7ZjdDTrTPWnNzWFhALoFe79UKw4lhE7
ezrqi0UCgYEA457BTvaKI+pcxuh5waV1SrfBYDC9czZpYht1R1i3lmYJKdQFHtVl
HAoy18zuYec9MaNPdqbzWysqkH6D6R8T/qdogQ9/5XpSnPVGbsg2IRKq4jNPrh1M
y8Kx2SOYpk6eLtPxYeRHaAKv/GYbQMs8Sh+GNkSiudhTEESj+KKhmO8CgYEA4e93
phLCmzP+SI2pgqFkZ2H2R5X8aCkbuV7pdcnTb4T/rH0Zah2vFEOmjWaUaGHJDOWk
6y+JPzWmxdweb+2FKTg1g6m8ig1DazcmkTG0CEWwwDLJ93LiQYl59uXt2UuQSkj6
Be+JcUzY2w1lhD0+vNfVF/RrH+xTaYfze1PiDxMCgYBtHNUdvSFLRjVjRF3Zbi9j
ueKA8dxfNl4eIXt+0BBxkEgkPPaXaUQmxNzKhfpgBDFZcifNgQp3UaH90if5wGQd
VrLJ61wr7Q9dHla9FEyeXgx8koxHstP1eUc4B9BNKLK7T+4ONxfjzCYAoBHAZaxo
++OicBRxcjmfOsg/j/ZXEQKBgQDZS84gfJSMXsIml5C7YWvGfpI2IUukBj1y2JTi
w1zGOf0IsTybMbdsXvA1uL3tcnbCH6+wvoRatcgTLfRcI+3ZSgU1/y6k+8KmwGEo
bcw/1H79KxvSEL0I2SbjThqmzaUVvQAya0IeJRHABC9pstm/GDoLkvjguBM1QRrs
ty2I3wKBgEBRpeSp/07x6LaIqHULNuV515BqtvWmWQuc8ngMOkcOO1mcQ745VbDj
YO0pIFHmK1iCtrXhyKPxOOitBjiQOZTeR6cZehm/7Mg+LWR6qdloqOOOij//WND6
PEeIskhUu6Dg07S91meHs3u/TRL0Gmr+zjCIn/0P40O38iyZTaVK
-----END RSA PRIVATE KEY-----
user4
user5
user6

De posse da chave privada, foi então questão de salvar em arquivo, que chamei de jenkins, e gerar a chave pública a partir dela.

Achei que o openssl iria fazer isso, mas todas as tentativas foram frustradas.  No fim descobri como resolver com o próprio ssh-keygen olhando no stackoverflow, sempre ele pra nos ajudar:

https://stackoverflow.com/questions/10271197/how-to-extract-public-key-using-openssl


> ssh-keygen -y -f jenkins
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABA
AABAQDI43N/VOLUO/yMjrz+jIYnYZ/oI2Q3ridxkBUHlCdH7Q1vLM0b1Tq4W
opShK65huWoA0k0ZHc8oJWEIkIHoZ7trM8rXR5gQcXJhca4jCL1FvcyyM0Kh
/ns3N6chRwSubQK7GTfjERd1HlQWbwYjSrcwS4FLCilB8Cd8Zrkv5DEa3/5i
5h6L+f9XRCyBi5lv1FUXY1tOs0uTT28FDtJXDIPMoFpoYWQ7S6Hp+8LP+Crw
v5/1wtn+3Bk3LX9nXdVJ7YCB3/USssGqVOvFps8IU8xabhiIADAhSqHBojoZ
TshEuj8daj16p+9hRaHoXIEpF/tt1J1Z9ZJJM3GDA8J8lq9

e foi assim que consegui conectar o Jenkins usando o user3 com chave ssh no Gitlab.  Peço desculpas em ter quebrado a chave em 60 colunas aqui, mas o fiz pra que ficasse bom pra ler também em smartphones.

AVISO: todos os dados aqui não são os verdadeiros.  Antes de alguém perder tempo usando isso pra tentar invadir alguma coisa minha, eu gerei tanto o ID com sha256sum da data atual e preenchi pra parecer o ID do Jenkins quanto a chave privada, que gerei também só pra mostrar aqui.  Nada disso está em uso em lugar algum.

O status code 103 de webservers

Details
Written by: Helio Loureiro
Category: Python
Published: November 06, 2021
Hits: 3128

E foi assim que tudo começou.  Com um singelo e modesto "deu merda".  Primeiramente uma rápida introdução pra explicar o que isso significa:  temos um bot pra adicionar assuntos nas pautas do canal Unix Load On.  O bot roda em Python no raspberrypi3 que tenho aqui em casa.  O mesmo que fica tirando fotos pela janela e mostra no twitter no perfil @helio_weather.

Então temos essa função "/addpauta" com um estilo de inglês a la Raimundos pra adicionar novos links.  O programa no bot rodava um código com módulo requests pra pegar a página e buscar o título do artigo.   Só isso.  Então não era algo esperado pra ter o resultado "deu merda".  Mas deu.

Olhando a mesma URL usando o ipython:

> ipython3
Python 3.9.7 (default, Sep 10 2021, 14:59:43) 
Type 'copyright', 'credits' or 'license' for more information
IPython 7.20.0 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import requests

In [2]: url = "https://www.theregister.com/2021/11/02/fedora_35/"

In [3]: r = requests.get(url)

In [4]: r.status_code
Out[4]: 103

In [5]: r.text
Out[5]: ''

então é isso.  O webserver retorna 103, que é uma nova RFC, e espera que você continue pegando o conteúdo.  Só que o módulo requests não faz isso.

Existe um bug aberto no github sobre esse problema onde eles relatam que o comportamento não é bem do requests, mas da urllib3, que é parte do core do Python.  Traduzindo em miúdos: não tem solução e talvez façam uma correção no Python 3.10.

Atualizar todo o Python só pra corrigir um erro besta desses?  Entra em cena o curl, que já comentei em usando curl pra monitorar um site.  Não o curl propriamente dito, mas a pycurl.  Tanto curl quanto pycurl passam dando tchauzinho por esse problema de manipular a resposta 103.  E mandam aquele abraço pra urllib3.

Olhando via script:

> curl -s https://www.theregister.com/2021/11/02/fedora_35/ | head -10
<!doctype html>
<html lang="en">
<head>
    <meta content="text/html; charset=utf-8" http-equiv="Content-Type">
    <title>Fedora 35 released with GNOME 41 desktop • The Register</title>
    <meta name="robots" content="max-snippet:-1, max-image-preview:standard, max-video-preview:0">
    <meta name="viewport" content="initial-scale=1.0, width=device-width"/>
    <meta property="og:image" content="https://regmedia.co.uk/2021/11/02/fedora35.jpg"/>
    <meta property="og:type" content="article" />
    <meta property="og:url" content="https://www.theregister.com/2021/11/02/fedora_35/" />

fazendo o mesmo em Python:

import pycurl
from io import BytesIO

def curl(url):
   crl = pycurl.Curl()
   crl.setopt(crl.URL, url)
   b_obj = BytesIO()
   crl.setopt(crl.WRITEDATA, b_obj)
   crl.setopt(crl.FOLLOWLOCATION, True)
   crl.setopt(pycurl.USERAGENT, 'Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0')
   crl.perform()
   crl.close()
   return b_obj.getvalue().decode('utf-8')

print(curl("https://www.theregister.com/2021/11/02/fedora_35/"))

então fica aqui a lição: onde a requests falhar, pycurl estará lá pra te salvar.

Latinoware 2021 - Go das trincheiras

Details
Written by: Helio Loureiro
Category: Go
Published: October 31, 2021
Hits: 4664

Eu até hoje não postei nada aqui, mas já faz algum tempo que trabalho com Go como primeira linguagem de programação.  É uma linguagem bacana e interessante.  A curva de aprendizado não é grande e rapidamente você já consegue criar programas nele.

Com essa ideia em mente eu refiz a palestrada da BSD Day, rápida introdução ao Python na BSD Day 2021, em Go.

 

Claro que é uma introdução bastante rápida e não cubro muitas coisas da linguagem.  Mas espero que sirva como primeiro passo pra quem estiver interessado em aprender.

Latinoware 2021 - carreira no exterior

Details
Written by: Helio Loureiro
Category: Suécia
Published: October 31, 2021
Hits: 3711

Eu acabei quebrando minha promessa de ano novo de postar aqui semanalmente durante os últimos meses.  Mas tenho uma boa justificativa.  Eu escrevi um artigo pra Revista Espírito Livre, fiz duas palestras na Latinoware, organizei a PyCon Suécia, organizei a hackathon na firma e fiz uma última palestra pra Tchelinux.

Muito disso ainda não foi publicado.  Quando aparecer, com certeza crio um post sobre o assunto.

Mas entre o que já foi publicado está a palestra sobre carreira na Latinoware.

 

Foquei mais nas perguntas que geralmente aparecem no grupo do telegram.  E, claro, tinha mais assunto pra falar, mas vou guardar pra outra oportunidade :)

Trabalhando de home-office - atualização de 2021 com teclado Keychron C1

Details
Written by: Helio Loureiro
Category: Blog
Published: October 31, 2021
Hits: 3948
  • teclado
  • keychron

Seguindo os artigos trabalhando de home-office e trabalhando de casa - atualização de 2021, aqui vai mais uma atualização.

Eu decidi investir num teclado novo.  Mecânico, claro.  Decidi não ter mais um full size, que tem o teclado numérico, mas num um pouco mais curto.  Depois de muito olhar e pesquisar, finalmente decidi pegar um Keychron C1 com brown switch.

Fiz um vídeo do unboxing onde tem até uma comparação de som com o teclado que usava anteriormente, que é do tipo blue switch.

Mas nem tudo foi uma maravilha em Linux.

Pra fazer o teclado funcionar corretamente eu precisei usar o modo Mac.  No modo Windows, de jeito nenhum eu consegui fazer funcionar as teclas de funções.  Mesmo no modo Mac eu precisei ajustar uns parâmetros pra tudo dar certo.

Precisei criar o arquivo /etc/moprobe.d/hid_apple.conf da seguinte maneira:

echo "options hid_apple fnmode=2 swap_opt_cmd=1" >> /etc/modprobe.d/hid_apple.conf

Com isso o kernel reconhece o teclado e aplica a configuração correta.  Então as teclas de função F1-F12 são o padrão e preciso apertar a tecla "fn" pra usar as funções.

Existem várias opções de troca de firmware pra mudar cores, etc, mas confesso que não é algo que eu realmente pense em fazer.   Pra mim basta ser um teclado mecânico confortável, o que realmente é, e ter um teclado luminoso (às vezes trabalho no escuro e isso ajuda).

Update em 2022-05-03

Como reinstalei meu laptop acabei percebendo que dica de cima faltaram algumas coisas.

Primeiro que pra ativar manualmente o teclado, basta rodar o seguinte comando como root:

echo 0 >> /sys/module/hid_apple/parameters/fnmode

depois que ao criar o arquivo no modprobe, é preciso também re-gerar o arquivo de initram com o comando:

update-initramfs -u -k all

Update em 2025-03-09: Atualizado o comando em /etc/modprobe.d/hid_apple.conf com a configuração atual.

Usando a GPU para renderizar vídeo

Details
Written by: Helio Loureiro
Category: Linux
Published: October 31, 2021
Hits: 4932

Durante a útima gravação do Unix Load On, Ingo comentou sobre aceleração de hardware via VAAPI.  Eu imaginava que isso apenas era possível com GPUs da NVIDIA, mas depois que ele comentou sobre VAPI rodando em Intel, fui atrás de como isso funcionava.

Então fiz o teste de criar um vídeo a partir das imagens que fiz da troca de pneus da bicicleta pros de inverno.

O primeiro foi usando a CPU.

  $ rm -f out.mp4; time ffmpeg -r 60 -i image-%03d.jpg -c:v libx264 -vf fps=60 -pix_fmt yuv420p out.mp4                                                                                                          
  ffmpeg version 3.4.8-0ubuntu0.2 Copyright (c) 2000-2020 the FFmpeg developers
    built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
    configuration: --prefix=/usr --extra-version=0ubuntu0.2
    --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu
    --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping
    --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa
    --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca
    --enable-libcdio --enable-libflite --enable-libfontconfig
    --enable-libfreetype --enable-libfribidi --enable-libgme
    --enable-libgsm --enable-libmp3lame --enable-libmysofa
    --enable-libopenjpeg --enable-libopenmpt --enable-libopus
    --enable-libpulse --enable-librubberband --enable-librsvg
    --enable-libshine --enable-libsnappy --enable-libsoxr
    --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame
    --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp
    --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq
    --enable-libzvbi --enable-omx --enable-openal --enable-opengl
    --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883
    --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264
    --enable-shared
    libavutil      55. 78.100 / 55. 78.100
    libavcodec     57.107.100 / 57.107.100
    libavformat    57. 83.100 / 57. 83.100
    libavdevice    57. 10.100 / 57. 10.100
    libavfilter     6.107.100 /  6.107.100
    libavresample   3.  7.  0 /  3.  7.  0
    libswscale      4.  8.100 /  4.  8.100
    libswresample   2.  9.100 /  2.  9.100
    libpostproc    54.  7.100 / 54.  7.100
  Input #0, image2, from 'image-%03d.jpg':
    Duration: 00:00:25.24, start: 0.000000, bitrate: N/A
      Stream #0:0: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown),
      4000x3000 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 25 tbn, 25 tbc
  Stream mapping:
    Stream #0:0 -> #0:0 (mjpeg (native) -> h264 (libx264))
  Press [q] to stop, [?] for help
  [swscaler @ 0x56448c3106c0] deprecated pixel format used, make sure you did set range correctly
  [libx264 @ 0x56448c268ee0] using SAR=1/1
  [libx264 @ 0x56448c268ee0] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2 AVX2
  [libx264 @ 0x56448c268ee0] profile High, level 6.0
  [libx264 @ 0x56448c268ee0] 264 - core 152 r2854 e9a5903 - H.264/MPEG-4
  AVC codec - Copyleft 2003-2017 - http://www.videolan.org/x264.html -
  options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7
  psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1
  8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=6
  lookahead_threads=1 sliced_threads=0 nr=0 decimate=1 interlaced=0
  bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1
  b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=250 keyint_min=25
  scenecut=40 intra_refresh=0 rc_lookahead=40 rc=crf mbtree=1 crf=23.0
  qcomp=0.60 qpmin=0 qpmax=69 qpstep=4 ip_ratio=1.40 aq=1:1.00
  Output #0, mp4, to 'out.mp4':
    Metadata:
      encoder         : Lavf57.83.100
      Stream #0:0: Video: h264 (libx264) (avc1 / 0x31637661), yuv420p,
      4000x3000 [SAR 1:1 DAR 4:3], q=-1--1, 60 fps, 15360 tbn, 60 tbc
      Metadata:
        encoder         : Lavc57.107.100 libx264
      Side data:
        cpb: bitrate max/min/avg: 0/0/0 buffer size: 0 vbv_delay: -1
  frame=  631 fps=1.1 q=-1.0 Lsize=   64381kB time=00:00:10.46 bitrate=50388.8kbits/s speed=0.0188x
  video:64372kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB muxing overhead: 0.013232%
  [libx264 @ 0x56448c268ee0] frame I:11    Avg QP:23.13  size:216485
  [libx264 @ 0x56448c268ee0] frame P:236   Avg QP:25.43  size:133712
  [libx264 @ 0x56448c268ee0] frame B:384   Avg QP:25.38  size: 83278
  [libx264 @ 0x56448c268ee0] consecutive B-frames: 14.1% 11.7%  7.6% 66.6%
  [libx264 @ 0x56448c268ee0] mb I  I16..4: 16.8% 81.8%  1.4%
  [libx264 @ 0x56448c268ee0] mb P  I16..4: 24.8% 44.9%  0.4%  P16..4:
  16.1%  1.8%  0.9%  0.0%  0.0%    skip:11.1%
  [libx264 @ 0x56448c268ee0] mb B  I16..4: 12.5% 18.4%  0.1%  B16..8:
  21.0%  2.2%  0.3%  direct: 2.5%  skip:43.1%  L0:50.8% L1:46.8% BI: 2.4%
  [libx264 @ 0x56448c268ee0] 8x8 transform intra:62.8% inter:92.5%
  [libx264 @ 0x56448c268ee0] coded y,uvDC,uvAC intra: 29.1% 18.4% 0.7% inter: 11.4% 16.9% 0.1%
  [libx264 @ 0x56448c268ee0] i16 v,h,dc,p: 41% 27% 23%  9%
  [libx264 @ 0x56448c268ee0] i8 v,h,dc,ddl,ddr,vr,hd,vl,hu: 29% 22% 42%  2%  1%  1%  1%  1%  1%
  [libx264 @ 0x56448c268ee0] i4 v,h,dc,ddl,ddr,vr,hd,vl,hu: 31% 17% 19%  6%  6%  6%  6%  5%  3%
  [libx264 @ 0x56448c268ee0] i8c dc,h,v,p: 66% 16% 18%  1%
  [libx264 @ 0x56448c268ee0] Weighted P-Frames: Y:33.5% UV:16.5%
  [libx264 @ 0x56448c268ee0] ref P L0: 40.1% 13.1% 23.2% 17.1%  6.5%
  [libx264 @ 0x56448c268ee0] ref B L0: 59.5% 30.9%  9.6%
  [libx264 @ 0x56448c268ee0] ref B L1: 83.0% 17.0%
  [libx264 @ 0x56448c268ee0] kb/s:50142.36
  1190.99user 25.61system 9:17.29elapsed 218%CPU (0avgtext+0avgdata 2714684maxresident)k
  117280inputs+128944outputs (45major+630483minor)pagefaults 0swaps

9 minutos e 17 segundos.  Usando 218% de CPU, de um laptop com 4 CPUs.  Esse é o funcionamento normal.

E usando a GPU pra isso?  Eu demorei um pouco pra acertar os parâmetros pra usar a VAAPI, mas no fim deu certo.

  $ rm -f out.mp4; time ffmpeg -vaapi_device /dev/dri/renderD128 -r 60 -i image-%03d.jpg -vf 'format=nv12,hwupload,fps=60' -c:v h264_vaapi  -pix_fmt vaapi_vld out.mp4                                           
  ffmpeg version 3.4.8-0ubuntu0.2 Copyright (c) 2000-2020 the FFmpeg developers
    built with gcc 7 (Ubuntu 7.5.0-3ubuntu1~18.04)
    configuration: --prefix=/usr --extra-version=0ubuntu0.2
    --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu
    --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping
    --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa
    --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca
    --enable-libcdio --enable-libflite --enable-libfontconfig
    --enable-libfreetype --enable-libfribidi --enable-libgme
    --enable-libgsm --enable-libmp3lame --enable-libmysofa
    --enable-libopenjpeg --enable-libopenmpt --enable-libopus
    --enable-libpulse --enable-librubberband --enable-librsvg
    --enable-libshine --enable-libsnappy --enable-libsoxr
    --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame
    --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp
    --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq
    --enable-libzvbi --enable-omx --enable-openal --enable-opengl
    --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883
    --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264
    --enable-shared
    libavutil      55. 78.100 / 55. 78.100
    libavcodec     57.107.100 / 57.107.100
    libavformat    57. 83.100 / 57. 83.100
    libavdevice    57. 10.100 / 57. 10.100
    libavfilter     6.107.100 /  6.107.100
    libavresample   3.  7.  0 /  3.  7.  0
    libswscale      4.  8.100 /  4.  8.100
    libswresample   2.  9.100 /  2.  9.100
    libpostproc    54.  7.100 / 54.  7.100
  Input #0, image2, from 'image-%03d.jpg':
    Duration: 00:00:25.24, start: 0.000000, bitrate: N/A
      Stream #0:0: Video: mjpeg, yuvj420p(pc, bt470bg/unknown/unknown),
      4000x3000 [SAR 1:1 DAR 4:3], 25 fps, 25 tbr, 25 tbn, 25 tbc
  Stream mapping:
    Stream #0:0 -> #0:0 (mjpeg (native) -> h264 (h264_vaapi))
  Press [q] to stop, [?] for help
  [swscaler @ 0x5577c4cfb3c0] deprecated pixel format used, make sure you did set range correctly
  Output #0, mp4, to 'out.mp4':
    Metadata:
      encoder         : Lavf57.83.100
      Stream #0:0: Video: h264 (h264_vaapi) (High) (avc1 / 0x31637661),
      vaapi_vld, 4000x3000 [SAR 1:1 DAR 4:3], q=0-31, 60 fps, 15360 tbn,
      60 tbc
      Metadata:
        encoder         : Lavc57.107.100 h264_vaapi
  frame=  631 fps=9.3 q=-0.0 Lsize=  133604kB time=00:00:10.48
  bitrate=104401.7kbits/s speed=0.154x
  video:133596kB audio:0kB subtitle:0kB other streams:0kB global headers:0kB
  muxing overhead: 0.006032%
  59.94user 1.03system 1:08.18elapsed 89%CPU (0avgtext+0avgdata 120480maxresident)k
  3504inputs+267264outputs (0major+44766minor)pagefaults 0swaps

Resultado?  1 minuto e 08 segundos.  Incrível.  Usou 89% de CPU, o que significa que das 4 CPUs, uma somente ficou ocupada.  E não 100%, apenas 90%.

Realmente incrível.

Não são todos os formatos de vídeo que são suportados, mas pra ter esse desempenho acho que vale sacrificar os formatos pra gerar um simples mp4.

 UPDATE: 2021-11-01.  O vídeo que renderizei pros testes.

 

Países considerados os mais felizes do mundo escondem problemas graves - as crianças

Details
Written by: Helio Loureiro
Category: Suécia
Published: September 10, 2021
Hits: 4931

Um mural de mãos feito pelos alunos da escola pra celebrar o fim do semetres.  Várias marcas de mãos feitas com tintas variadas, um coração desenhado no meio e mostrando o ano, 2018.

Se você chegou agora e está perdido com o título, leia o primeiro artigo:

Países considerados os mais felizes do mundo escondem problemas graves

Pra você que leu e talvez não tenha ficado claro o motivo de eu abordar as fotos nas revistas no primeiro artigo:  eu tentei mostrar que existe uma exigência de padrão de beleza bem menor que em países como o Brasil.  Aqui cada um veste o que quiser e do jeito que quiser.  E, claro, isso contribui pra felicidade da população.

E agora vamos falar um pouco das crianças.  Falar sem ver.  Por quê?  Porque a maioria dos lugares que eu adoraria mostrar não permitem fotos.  Tive de recorrer ao Google Maps para pegar algumas, mas as partes mais legais não aparecem porque em geral as escolas ficam dentro de parques.

Primeiramente que escola é obrigatória aqui.  A partir dos... acho que 6 anos (mas posso estar enganado, então pode ser que seja aos 7).  Começa no förskola (fer-is-cuo-la), ou primeira escola (primário), e depois vai do 1° ao 9˘ ano.  A partir daí é o colegial de 3 anos.  A escola em geral é gratuita, paga pelos impostos, mas descobri recentemente que alguma escolas internacionais em inglês são pagas.    Existem escolas em inglês que não são pagas, mas essas têm filas de 4, 5, e até mais anos.  Em geral é uma boa a escola em sueco pra criançada pegar o idioma, mas isso vai da decisão dos pais e suas possibilidades.

Independentemente de onde morar, é obrigatório a cidade oferecer uma vaga em até 3 meses na escola sueca.  Isso pode ser doloroso se estiver com aluguel de moradia curta de 6 meses, que é meio que regra aqui (e isso é muito ruim).

Na escola são dados materiais didáticos como cadernos, livros e canetas ou lápis.  Então basicamente você só precisa deixar a criança na escola e buscar depois.  Sobre o horário, muitas escolas abrem por volta das 6:30 da manhã, pra permitir aos pais que trabalham ou longe ou nesse horário pra ter onde deixar as crianças.  Pra buscar pode ser até às 7:30 da noite.  Mas se não me engano isso é de algumas escolas e o horário obrigatório é às 06:30 da tarde.   Na escola recebem alimentação pra ficar o dia inteiro.  E já esquecia desse ponto: as escolas são o dia todo.

Foto de um papel com um calendário desenhado pro uma criança, que contava os dias até o natal.

Além das aulas normais como de língua e matemática, nas escolas têm também aulas de culinária, marcenaria e costura.  Não aquela maravilha, mas vez ou outra sai umas  pizzas de forno (pão árabe, molho de tomate, presunto e queijo).  É comum também a escola levar a turma toda pra passeios em fazendas com animais.  Por quê?  Pra conhecerem os animais.  Então eles brincam com os coelhos, correm das galinhas e dão comida pros pôneis.  A escola também os leva pra aproveitar as piscinas indoor durante o inverno e a outdoor, que é bem rasinha, no verão.  Tem também passeios durante o inverno pra patinarem no gelo e, no ponto mais central, até esquiarem (existe um morro famoso aqui no centro que permite isso e não é muito alto).  Na escola ainda eles têm direito a 1 hora de aula da língua materna por semana.

Pra deixar bem claro: não é escola com aulas o dia todo, mas pra ter onde deixar as crianças.  A escola começa por volta das 8:30 e termina por volta das 14:00.  Alguns dias um pouco mais tarde, em outros um pouco mais cedo.   Desde o começo já aprendem a andar pela cidade.  Todas as atividades são ou nos parques ao redor das escolas ou em museus que em geral ficam em algum lugar distante, mais central, ou ainda nas tais fazendo que mencionei acima.  Então as crianças desde pesquenas são orientadas em como usar o transporte público.  Que é gratuito até os 8 anos.  E depois?  Continua gratuito pra maiores de 8 anos que precisam pegar transporte público pra ira à escola.  Eles oferecem um cartão que não paga nada até às 7:30 da noite durante a semana.  E, claro, o transporte de estudantes custa mais barato que o passe normal, caso precise comprar passagem pro fim de semana.

Imagem de crianças andando juntas com vestes amarelas para identificação.  Todas estão de costas para não serem identificadas.

 Em geral as escolas são próximas das residências.  Ao ponto das crianças irem sozinhas já com 7 ou 8 anos.  E eles incentivam isso.  Quando chegam numa certa idade, do ginásio, daí são escolas maiores e geralmente poucas por bairros.  E assim as escolas vão afunilando a localização conforme a criança vai crescendo.  É comum ver jovens indo pra escola de bicicleta.  Pra mostrar um pouco das escolas, vou recorrer ao Google Maps pelo motivo que já coloquei logo no começo do artigo: privacidade das crianças e adolescentes.

Foto do Google maps que mostra a entrada de uma escola primária num parque.

Foto de uma escola de alunos do ginásio.  Um prédio com 9 janelas, 3 por andar.  Na rua em frente um trator parado.

Foto do Google Maps que parece uma escola ao fundo com um playground na frente.  Eu não tenho bem certeza se esse prédio é uma escola.

E antes que me esqueça, aqui tem também uma bolsa pra cada filho melhor.  É chamado barnbidrag e vem metade pro pai e metade pra mãe, mesmo sendo casados.  Pra, no caso de separação e/ou divórcio, ficar tudo mais fácil.   É como uma bolsa família mas com a diferença de que todo mundo recebe, independentemente se sua renda mensal precisa ou não.  Não é um valor alto, por volta de 100 euros, mas é um dinheiro da criançada pra gastar com a criançada.

Bom... já descrevi da escola, mas onde está a parte relevante?  Onde está a parte que a Suécia esconde?

Aqui é comum ver as crianças, quando mais jovens, irem vestidas... como quiserem.  Meninos vão de vestido e meninas vão de vaqueiro.   Não existe um "menino usa azul e menina usa rosa", que é até considerado sexismo por aqui.  Tanto que uma loja de brinquedos viu-se no meio de uma discussão sobre sexismo ao separar os brinquedos em sessões "de meninos" e "de meninas".

Foto do Google Maps mostrando outro local de uma escola.  Mas como fica no meio do parque não é possível ver detalhadamente.  Aparece na foto um gramado grande, árvores e um prédio comprido de 2 andares ao fundo.

Pandemia

E como foram as escolas durante a pandemia?  Certo ou errado, a Suécia manteve a decisão de permanecer com escolas abertas até o 9° ano, pois o argumento foi de que era preciso manter as crianças na escola pros pais que trabalhavam na linha de frente pudessem continuar trabalhando.  Apenas os jovens do colegial passaram a ter aulas remotas.  E, claro, cada um recebeu um laptop pra poder participar das aulas.  Nas universidades também as aulas passaram pro modo remoto, mas não sei dizer se receberam um laptop pra isso ou não.

As ideias finais

Tá certo... mas isso não explica a reclamação dos pais moçambicanos, não é mesmo?  O que acontece aqui é que a Suécia trata cada criança como uma cidadã desde pequena.  Ao contrário de países como Brasil, onde os pais é que são seus guardiões, aqui o estado representa a criança e seus interesses.  Inclusive contra os próprios pais, se for o caso.  Então se um pai abusivo entrar em casa e bater numa criança, ou jovem, pode ser denunciado por esse à polícia.  É uma noção bastante estranha pra nós brasileiros, mas com o tempo você acaba acostumando (ou então volta pro seu país).

Existe uma discussão sobre a Suécia estar criando pequenos ditadores nesse sentido.  Mas eu diria que isso é um estigma de quem vem de fora e quer criar caso.   Ninguém comenta do sistema de ensino, das escolas gratuitas e só olham pra esse lado.  Claro que é mais fácil apontar pra um defeito, mas esquecer tudo mais que se ganha aqui?

Leva-se um tempo pra acostumar com as regras daqui e passar a tratar os filhos como... cidadãos.   Então como qualquer outra pessoa, você tem de sempre negociar.  Não vai tomar banho?  Não tem Internet.  Não vai pra escola?  Não tem youtube.  E por aí vai.  Não, não é tarefa fácil, como atestam os moçambicanos.

Mas falar de brasileiros ou moçambicanos pode até dar a ideia errada sobre o que está por trás disso.  O que acontece é que nem todo mundo compartilha os valores europeus.  E pra estar aqui, deveriam adaptar-se.  Então as famosas mutilações de genitais, praticadas em vários países do mundo, não é permitida aqui.  A criança pode denunciar os pais por tentarem fazer isso e pode ser direcionada pra viver com sob guarda do estado.

Estranho uma criança tendo direitos, não é?  Mas não devia ser.  Aqui não é.

 

Países considerados os mais felizes do mundo escondem problemas graves

Details
Written by: Helio Loureiro
Category: Suécia
Published: September 07, 2021
Hits: 4961

Então recebi assim, sem muita cerimônia, a reportagem da Record sobre a Suécia.  Países considerados os mais felizes do mundo escondem problemas graves.  O título já é um grande bait. A coisa toda vai de mau a pior.  É um monte de bobagens juntas com vários estereótipos juntos.

Fonte: https://recordtv.r7.com/domingo-espetacular/videos/paises-considerados-os-mais-felizes-do-mundo-escondem-problemas-graves-16082021

Não é a primeira vez que recebo algo assim e provavelmente não será a última.  Minha sensação é que pra esconder a atual situação, que eles ajudaram a chegar com várias reportagens de apoio ao atual presidente, ficam despejando esse conteúdo de vira-latas.  Algo pra dizer "olha como não somos só nós que estamos mal, e eles escondem muitos problemas".  Claro que existem problemas aqui, mas não como no Brasil.

Então vou escrever um pouco mais sobre a Suécia e tentar mostrar pelo menos outro tipo de visão da coisa.

E escolhi escreve sobre... propaganda!  Sim, propaganda.

Aqui usa-se muito a imagem das pessoas como elas são, sem muita maquiagem, nem sensualização.   Então não é um povo que vê sexo em tudo que vê, nem leva tudo pra um lado erótico.  Pelo contrário.

Uns exemplos tirados de revistas.  Nesse primeiro temos uma mulher... trocando o pneu.  E duvido que seja apenas pra aparecer na capa da revista.  Aqui a igualdade é levada ao extremo é comum ver mulheres trabalhando em empregos que tipicamente temos somente homens no Brasil, como construção civil.

Revista com mulher loira levantando um carro pra trocar o pneu.  Ela usa calça jeans azul, um moletom cinza e tem um trança longa no cabelo loiro.  Usa pouca ou nenhuma maquiagem.

Essa é a revista do sindicato.  Eu sou sindicalizado aqui e faço parte do Unionen, um dos maiore sindicatos da Suécia.  Na capa da revista é possível ver outra mulher e... nada de pose sensual.  Pouco maquiagem.  Apenas ela.  E não é só nas revistas.  Normalmente as mulheres aqui não usam muita maquiagem.  Nem vestem-se de maneira muito chique.

Revista Kolega do sindicato da Suécia chamado Unionen com uma mulher ruiva usando uma jaqueta cor laranja.  Foto de lado mostrando que carrega uma bolsa.

Essa parte interna da revista tem uma propaganda com essa mulher acidentada.  Novamente nada de maquiagem, ou ao menos que possa mostrar sensualidade.  Se não me engano era um anúncio de seguro.

Mulher loira com pouca maquiagem, segurando um telefone numa mão e a roda de uma bicileta na outra.  Ela usa capacete e parece olhar para frente pensando em alguma coisa.

Um artigo sobre uma fazenda de animais ou algo assim.  Notem novamente a pessoa na foto.  Sem muita maquiagem e com roupas simples.

Mulher ruiva sentada no chão com seu cachorro ao lado.  Ela usando pouca maquiagem e roupas simples: uma jaqueta verde no estilo camuflada, uma camisa preta com bolinhas brancas e calça preta.  Ao fundo um viveiro com galinhas.

Agora uma reportagem interna sobre um treinador de futebol pra crianças.  Novamente uma pessoa como ela é: sem roupas marcantes, sem ser aquele sueco super sensual e fortão.  Apenas uma pessoa com cara de gente boa e fazendo algo que inspira outros a fazerem igual.

Homem louro com cabelo despenteado ajoelhado e segurando uma bola.  Veste uma camiseta da Adidas vermelha e calça preta.  Crianças correm ao redor dele de forma animada.

E essa bela foto dessa vovó simpática então?  Novamente pouca produção e a pessoa mais próxima do que realmente é em seu cotidiano.

Uma foto de rosto de uma idosa sorridente com cabelos grisalhos curto e óculos.

Aqui mais um homem, desses que a gente se identifica.  Não aqueles deuses nórdicos que a mulheres acham que vão ver o tempo todo na Suécia.  Esse sim um típico sueco.

Homem sentado em sofá azul.  Cabelos louros escuro com um pullover laranja, calça marrom e tênis branco.

E mais uma foto de propaganda na revista.  Agora de um casal em posição de... nada.  Apenas olhando o telefone juntos.  Ambos usando roupas comuns e ela com um pouco de batom.  E só.  Bem simples, e bem cotidiano.

Casal de jovens sentados em uma cadeira grande olhando juntos a tela de um telefone.  Ele de jaqueta azul, camiseta rosa e bermuda cinza.  Ela de jaqueta jeans azul.

A última foto de mulher nesse artigo.  Sem muita maquiagem e cabelos no mais natural possível.

Foto de rosto de uma mulher loura com cabelo desarrumado.

E finalmente a capa da outra revista que mostrei a parte de dentro, o guia de saúde que recebemos a cada 3 meses.  Novamente um homem sueco com cara de sueco mesmo.  Simples, de óculos, com apenas uma blusa e nada estravagante.

Homem com cabelo louro escuro e óculos numa paisagem cheia de vegetação.

Acho que até aqui já foi possível entender como as coisas funcionam aqui.  O que existe no Brasil como normal em termos de propaganda com certeza seria tido como vulgar aqui.  Eu mesmo depois desse tempo todo já vejo como vulgar, imagina então eles?   E esse zen de vestir-se e viver de forma simples está em todo lugar.   Algumas pessoas vão pra empresa de terno, mas maioria não vai.  Aliás não existe um "dress code".  Veste-se o que quer e como quer.  Eu até acredito que é possível ir com a cueca por fora da calça que ninguém vai falar nada.

Então a Suécia figura como um dos países mais felizes do mundo.  Um dos motivos é esse: simplicidade.  Em tudo.

 

  • Obama está observando você
  • Latinoware 2021
  • A briga entre Docker e firewalld
  • Usando expect pra acessar um host no meio do caminho
  • Uma conversa introdutória sobre shell scripts com o prof. Juliano

Page 14 of 40

  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

Estatísticas

  • Users 2
  • Articles 519
  • Articles View Hits 3757247

Imagem aleatória