quinta-feira, 28 de dezembro de 2023

Minha Teoria de Tudo

Eu imagino que todo mundo conheça algum senhor de uma certa idade que tenha uma "teoria de tudo". Penso isso, porque já conheci várias figuras assim. Geralmente são aposentados e conseguem reduzir todos os problemas do mundo ao excesso de gente, ou à falta de polícia, ou ao comunismo, etc.

Ainda estou longe de me aposentar, tão longe que eu acho que sequer vou chegar lá: um dia, eu digo aos meus colegas, vou deixar de vir ao trabalho. Entretanto, já começa a se formar na minha cabeça uma teoria de tudo.

Durante a pandemia, comecei a assistir muitos vídeos sobre filosofia. Em parte por interesse no assunto, em parte porque Kant me ajudava a dormir. Um fato curioso começou a se desenhar: há muitos canais de filosofia apresentados por pessoas trans ou drag-queens. Pode ser também que o Youtube tenha decidido que, de todos os canais de filosofia, eu prefira esses.

O último que apareceu para mim é o Philosophy Tube, apresentado por uma Abigail Thorn. E o episódio que surgiu para mim era sobre construções sociais. É uma apresentação bastante convincente sobre a aribtrariedade das normas da sociedade. Naturalmente, uma pessoa que viva fora das convenções, como Abigail Thorn, deve perceber com maior claridade as limitações dessas normas.

Concorrentemente, estou lendo um livro sobre autismo (Unmasking Autism - Devon Price), mais especificamente sobre mascaramento. Logo na introdução há uma referência a Hannah Gadbsy, uma comediante autista e que, num de seus esquetes, fala sobre sua dificuldade na escola. A dificuldade, naturalmente, advém da incapacidade de pensar na mesma frequência que a professora.

Essa força em direção ao conformismo que vivenciamos na sociedade, sendo causa ou consequência, não sei bem ainda, age no sentido de manter o status quo.

As religiões costumam ter um credo; o catolicismo obriga as pessoas a repetir o credo em todas as missas (pelo menos todas a que eu fui). É um momento estranho: se eu acredito mesmo nisso, por que tenho que ficar repetindo? Não acordo todo dia e repito: a terra é redonda, orbita o sol, e as espécies evoluem através da seleção natural.

Tem um trecho da quinta sinfonia de Shostakovich que ele descreve como:

É como se alguém estivesse batendo em você com um pedaço de pau e dizendo: “Seu negócio é alegria, seu negócio é alegria”, e você se levanta, trêmulo, e sai marchando, murmurando: “Nosso negócio é alegria, nosso negócio é alegria”.

O problema, como eu o vejo, é que muita gente sai mesmo marchando com alegria. A superestrutura dá um tapa na cara do sujeito e ele ainda não a enxerga.

Esses defeitos na matriz aparecem em outros lugares, não apenas na religião. Aparecem na insistência da mídia corporativa com os ideais neoliberais; aparecem em cartazes com "Eu confio na Polícia"; e até nas renovações anuais dos "valores" das empresas. Essas coisas lembram os cartazes ufanistas dos países comunistas: Glória ao Povo Soviético Rumo ao Comunismo! Pelo menos a arte era melhor e tinham mosaicos.

O que terão de especial as drag-queens e os autistas? Os primeiros sofrem por não se adequarem às normas, os segundos por não entenderem as normas.

Mas, se as construções sociais são arbitrárias, podemos imaginar um mundo em que os autistas e as drag-queens sejam os heróis da sociedade: eles percebem o que é supérfluo! Deficientes são aqueles que acreditam nas arbitrariedades da sociedade como se fossem uma lei natural e acreditam com tal força que acham-se no direito até de usar de violência física, verbal, ou qual seja, para reafirmar suas crenças.

Quem é deficiente ou não é também uma construção social.

E então chego a meu diagnóstico que tudo abrange: o problema da sociedade é que deixamos as pessoas deficientes organizarem tudo.

sábado, 11 de novembro de 2023

Presensocial

O escritório está a 5km de minha casa, mas entre levar as crianças ao colégio e dar carona à esposa, levo pelo menos uma hora para chegar lá. O trajeto todo tem uns 15km, então a velocidade média é de 15km/h. Péssimo.

Chego ao escritório cedo para ter tempo de verificar a situação antes que as interrupções iniciem. Dá tempo para resolver alguns chamados e talvez até corrigir um bug. Meia hora mais tarde, já começam a chegar pessoas assobiando pelo corredor. Alguém entra na sala para perguntar se o chefe está; alguém pede ajuda com a impressora ou com o wifi.

Uma vez que o escritório esteja cheio, começam as reuniões improvisadas, as reuniões remotas simultâneas, as ligações equivocadas, e uma miríade de interrupções, algumas até divertidas.

Trabalhar para valer, é difícil. Talvez dê para resolver algo à tarde.

O segredo da felicidade são as baixas expectativas. Não adianta sonhar em ser muito produtivo num cenário destes. Já vi piores: já trabalhei no meio de uma reforma, numa sala com 60 pessoas.

Penso que talvez essa ânsia pela volta ao trabalho presencial seja um conflito de gerações. As pessoas no topo da hierarquia costumam ser mais velhas; talvez os filhos já tenham crescido e talvez ficar em casa sozinho seja um pouco triste. Ou talvez o trabalho de quem gerencia seja essencialmente político e social. Quero crer que não seja por maldade, embora não seja, digamos, muito inteligente.

Os gringos já inventaram o termo coffee-badging. O sujeito vai ao escritório, bate o ponto, toma um café com os colegas, e volta para casa para trabalhar de verdade. Para mim, não seria uma solução, porque eu queria justamente evitar ter que ir ao escritório todos os dias. Uma vez ou duas por semana seriam suficientes.

Coffee-badging é um bom termo, mas eu queria algo mais próximo da nossa língua. Ocorreu-me "presensocial". Se falar rápido, o chefe nem vai perceber a ironia.

Evidentemente, menos resultados são produzidos. E eu certamente não vou chegar a casa depois de 2h no trânsito naquele dia para ligar o micro. Durante a pandemia, eu trabalhava muito mais que as minhas horas e consegui fazer muitas coisas boas.

Parece que a firma não está interessada no meu trabalho, mas na minha companhia. Acho que a firma precisa de apoio psicológico.

terça-feira, 31 de outubro de 2023

Fizzbuzz com closures

Dado que a solução com recursão tinha duas funções bem parecidas, o natural é subir um nível na abstração e criar uma função para criar funções.


#!/usr/bin/perl
use strict;
use warnings;
no warnings 'recursion';

sub make_fizzbuzz {
  my ($callback, $factor, $word)=@_;

  return sub {
    my $n=shift || 1;
    my $multiple=shift || 0;

    if($n % $factor == 0) {
      print $word;
      $multiple=1;
    }

    $callback->($n, $multiple);
  }
}

my $fizzbuzz;

$fizzbuzz=make_fizzbuzz(make_fizzbuzz(sub {
  my ($n, $multiple)=@_;

  print $n if !$multiple;
  print "\n";
  $fizzbuzz->($n+1) if $n<1000;
}, 5, 'buzz'), 3, 'fizz');

$fizzbuzz->();

Dado que o código recursivamente cria uma recursão, parece natural começar pelo fim, então a primeira função passada é o caso especial e ela também é uma closure, porque precisa referenciar o ponto de partida.

Depois disso, podemos adicionar mais casos facilmente:


$fizzbuzz=make_fizzbuzz(make_fizzbuzz(make_fizzbuzz(make_fizzbuzz(sub {
  my ($n, $multiple)=@_;

  print $n if !$multiple;
  print "\n";
  $fizzbuzz->($n+1) if $n<1000;
}, 5, 'buzz'), 3, 'fizz'), 7, 'crackle'), 11, 'pop');

Bem elegante, na minha opinião.

segunda-feira, 30 de outubro de 2023

Fizzbuzz recursivo

Uma construção interessante que não cheguei a usar profissionalmente é a recursão mútua: A() chama B() que chama A() e assim por diante.

Entretanto, pesquisando uma solução recursiva para o Fizzbuzz, ocorreu-me uma estrutura com 3 funções em uma recursão circular. Não tem esse nome no Google, mas parece uma maneira natural de descrever o código que segue.

Teremos uma função para os múltiplos de 3, uma para os múltiplos 5, e uma para o que sobrar. A primeira chama a segunda, que chama a última, que chama novamente a primeira, e segue a loucura.


#!/usr/bin/perl
use strict;
use warnings;
no warnings 'recursion';

sub threes {
  my $n=shift || 1;
  my $multiple=0;

  if($n % 3 == 0) {
    print 'fizz';
    $multiple=1;
  }

  fives($n, $multiple);
}

sub fives {
  my ($n, $multiple)=@_;

  if($n % 5 == 0) {
    print 'buzz';
    $multiple=1;
  }

  rest($n, $multiple);
}

sub rest {
  my ($n, $multiple)=@_;

  print $n if !$multiple;
  print "\n";
  threes($n+1) if $n<1000;
}

threes();  

Parece que ainda há coisas na programação que precisam de nomes.

terça-feira, 10 de outubro de 2023

FizzBuzz genérico

O FizzBuzz deveria ser um exercício de lógica, mas é muito mais divertido como um exercício de matemática.

No post anterior, vimos como os valores podem ser mapeados facilmente usando n4 mod 15.

Esse expoente é o MMC dos valores das totientes de 3 e 5 (que chamarei de chaves). A função totiente conta todos os números inferiores a n que não possuem fatores comuns com n.

O 15 é o produto de 3 e 5. A solução pode ser generalizada para qualquer conjunto de números primos. Ela fica um pouco mais complicada quando o conjunto tem mais de 2 elementos, porque é necessário calcular os valores um a um, depois dois a dois, e assim sucessivamente.

Então, nossos elementos de trabalho são:

  • Um expoente e (MMC dos totientes das chaves);
  • Um modulo m (produtos das chaves);
  • Para cada combinação de chaves, um valor v=pe mod m, sendo p o produto do subconjunto das chaves.

O produto de todas as chaves (no caso inicial, 3*5=15) mapeia para 0 (n4 mod 15 = 0 quando n é múltiplo de 3 e 5).

Quando o resto da conta for 1, de acordo com o teorema da Euler, isso significa que o valor é relativamente primo a 3 e 5.

O código a seguir junta tudo:


#!/usr/bin/perl
use bigint;
use Math::Utils qw(gcd lcm);
use strict;

sub phi {
  my $n=shift;
  my $phi=1;

  return 1 if $n<3;

  for my $i (2..$n-1) {
    $phi++ if gcd($n, $i) == 1;
  }

  return $phi;
}

sub choose {
  my $n=shift;
  my $k=shift;
  my $callback=shift;
  my @rest=@_;
  
  if($k>0) {
    for my $m ($k..$n) {
      choose($m-1, $k-1, $callback, $m, @rest); 
      &$callback($m, @rest) if $k==1;
    }
  } 
}

sub generic_fizz_buzz {
  my $parms=shift;
  my @keys=keys %$parms;

  # Todos e nenhum
  my $fizz_buzz_map={
    0 => sub { join('', values %$parms) }, 
    1 => sub { shift },
  };

  my $e=lcm(map { phi($_) } @keys);
  my $m=1;
  map { $m*=$_ } @keys;

  # Os elementos de 1 a 1, 2 a 2, etc
  for my $n (1..scalar(@keys)-1) {
    choose(scalar(@keys), $n, sub {
      my $key=1;
      my $value;
      map { $key*=$keys[$_-1] } @_;
      my $r=join '', map { $parms->{$keys[$_-1]}} @_;
      $fizz_buzz_map->{$key**$e % $m} = sub { $r };
    });
  }

  for(1..99) {
    print $fizz_buzz_map->{$_**$e % $m}->($_)."\n";
  }
}

generic_fizz_buzz({ 3=> 'fizz', 5=>'buzz', 7=>'crackle', 11=>'pop'});

A funcção generica_fizz_buzz() recebe uma referência a um hash que mapeia números a strings. Como uso hashes, as concatenações dos strings podem sair em qualquer ordem, mas isso não é importante.


1
2
fizz
4
buzz
fizz
crackle
8
fizz
buzz
pop
fizz
13
crackle
buzzfizz
16
17
fizz
19
buzz
fizzcrackle
pop
23
fizz
buzz
26
fizz
crackle
29
buzzfizz
31
32
fizzpop
34
buzzcrackle

Com 5 e 13, o expoente é 12, o módulo é 65 (5*13), e o mapeamento tem esta cara:


 {
   '40' => sub { "fizz" },
   '26' => sub { "buzz" },
    '0' => sub { "fizzbuzz" },
    '1' => sub { shift }
 };

Parece que funciona. Pontos para Euler.

sexta-feira, 6 de outubro de 2023

FizzBuzz sem ifs

Uma questão que supostamente aparece em entrevistas para cargos de programação é o FizzBuzz. O enunciado é simples: imprima todos os números de 1 a n, mas imprima fizz para os múltiplos de 3, buzz para os múltiplos de 5, e fizzbuzz para os múltiplos de 3 e 5.

Sabemos que 3 e 5 são relativamente primos, então eles só vão juntos dividir n a cada 15 valores.

Um solução óbvia, então, é usar um pequeno mapeamento:


#!/usr/bin/perl
use strict;

for(1..99) {
  print [
    'fizzbuzz', 
    $_, 
    $_, 
    'fizz', 
    $_, 
    'buzz', 
    'fizz', 
    $_, 
    $_, 
    'fizz', 
    'buzz', 
    $_, 
    'fizz', 
    $_, 
    $_]->[$_%15]."\n";
}

Tudo bem, não tão óbvia como usar uma sequência de ifs.

Agora, não quero recriar o array dentro do loop a cada iteração, então vou tirá-lo e trocar os valores por funções. Algumas funções retornam o número que for passado como parâmetro, outras passam fizz, ou buzz, ou fizzbuzz.

Adicionei uma pequena otimização: o mapeamento é espelhado pela metade. O resultado do espelhamento tem uma posição extra, mas isso não incomoda.


#!/usr/bin/perl
use strict;

my @map=(
    sub {'fizzbuzz'},
    sub {shift},
    sub {shift},
    sub {'fizz'},
    sub {shift},
    sub {'buzz'},
    sub {'fizz'},
    sub {shift}
);
push @map, reverse @map;

for(1..99) {
  print $map[$_%15]->($_)."\n";
}

Com um pouquinho de mágica, podemos simplificar ainda mais. Resulta que o resto de n4 por 15 só produz os valores 0, 1, 6, e 10. Magicamente, podemos mapeá-los diretamente ao que queremos:


#!/usr/bin/perl
use strict;

my %map=(
    0 => sub {'fizzbuzz'},
    1 => sub {shift},
    6 => sub {'fizz'},
    10=> sub {'buzz'}
);

for(1..99) {
  print $map{$_**4%15}->($_)."\n";
}

Os detalhes dessa solução e a generalização para quaisquer outros números estão neste artigo.

Se alguém for usar uma solução dessas numa entrevista, recomendo explicar direitinho que não vai fazer isso com o código da empresa.

quarta-feira, 4 de outubro de 2023

Novas placas de carros

Certa vez, um motorista de Uber apontou para mim que as placas novas não permitiam identificar se certos símbolos eram número ou letra. Eu tentei argumentar, explicando que em cada posição só podia haver um número ou uma letra. Infelizmente, o compatriota não alcançou a captar a minha explicação. A derrota foi mútua.

De qualquer forma, tenho notado que algumas placas são perigosamente parecidas a palavras. Resolvi baixar um dicionário e testar quantas podem haver com palavras. Usei a versão sem acentos de uma lista qualquer da internet.

Eu sinto falta é da indicação de estado e cidade.


grep -Po "^[a-z]{3}[oiasg][a-z][oiasg]{2}$" br-sem-acentos-txt | wc -l
3380

Mapeei 0 para O, 1 para I, 4 para A, 5 para S, e 6 para G. Como a lista de palavras está em caixa baixa, a expressão regular não é tão obvia. Em caixa alta ela tem sentido.

De um universo de 456.976.000 placas, apenas 3380 se parecem com palavras de 7 letras. Claro que há umas palavras "bonitas":


grep -Po "^[a-z]{3}[oiasg][a-z][oiasg]{2}$" br-sem-acentos-txt | grep bon
bonitas
bonitos

Será que CAS4D05 caiu para um solteiro e FEI0S05 para uma família bonita?

quinta-feira, 28 de setembro de 2023

A era do conteúdo

Ultimamente eu estive avaliando notebooks e comecei a assistir vídeos no Youtube. Infelizmente, todos são muito superficiais. Eles falam sobre as cores, se o micro é fininho ou não, quanto pesa, etc. A parte mais técnica é a enumeração das características básicas (CPU, memória, etc). Essa fixação com a espessura dos notebooks, por sinal, é de lascar, porque está levando a produtos que são impossíveis de consertar ou atualizar.

Então comecei a reparar o mesmo com os vídeos de carros. Os "analistas" descrevem as cores, o tipo de estofado, os itens do painel, etc. Nenhuma informação realmente elucidativa é incluída: quem se deparar com o produto pela primeira vez, já pode sair gravando um vídeo.

Quem acompanha os vloggers de tecnologia certamente testemunhou toda a comoção gerada pela revelação de que Linux Tech Tips publicava informações falsas simplesmente porque precisava gerar vídeos num ritmo acelerado. LTT se apresentava como um canal sério e que analisava a fundo os produtos. Sequer os canais grandes são confiáveis.

Tem uma categoria de vídeos que são aqueles sobre produtos baratos e descartáveis da China. Esses também são muito razos, principalmente porque o narrador abre o produto naquele momento e toma conhecimento dele enquanto grava. Entretanto, só pelo fato de manusear um objeto, já se pode ter uma ideia do tamanho e da qualidade. Algum valor marginal há nesses vídeos, embora assisti-los por completo talvez seja demais.

Uma categoria que acho patética é a dos vídeos de dicas domésticas, porque há uma tentativa desesperada de encontrar soluções inesperadas para tarefas ou objetos de uso cotidiano.

Os filosófos contemporâneos chamam nossa era de Capitalismo Tardio. Além do crescimento do comércio internacional, há também um aumento exponencial de produtos, assim como um aumento na velocidade na criação de novos produtos. Entretanto, isso não quer dizer que todos os produtos sejam de fato inovadores; muitas vezes a inovação é apenas estética e superficial. Por exemplo, eu escrevo estes textos num micro que tem mais de 10 anos (embora eu tenha executado muitas manutenções nele). Um micro novo seria interessante, mas não essencial para as minhas necessidades. Já se foi a época em que cada geração de computadores tinha o dobro de capacidade em tudo; a velocidade de lançamentos, entretanto, continua alta.

A evolução tecnológica vai colocando mais e mais poder na mão do indivíduo. A evolução nas comunicações certamente permitiu a qualquer um conquistar públicos no planeta inteiro. O que nem o plim-plim consegue, um youtuber pode fazer sozinho. Mas isso não significa que o conteúdo seja melhor.

Os jornalistas sempre nos alimentaram notícias desprovidas de informação. Cada jornal matinal com as mesmas informações sobre crimes, esportes, e o tempo podia ser repetido em qualquer outro dia.

Então esses criadores de conteúdo não são uma inovação, exceto pela quantidade e pelo ritmo de produção de pseudo-informação. A própria expressão "conteúdo" acho que revela a forma genérica e sem profundidade do que é produzido. Conteúdo é uma coisa que ocupa espaço e tempo, principalmente tempo. Como as TVs antes precisavam ser genéricas, os assuntos foram sempre os mais abrangentes. A tecnologia agora nos permite canais superficiais sobre qualquer tema.

Os jornalistas tradicionais podem se justificar com a necessidade de produzir diariamente conteúdo para uma massa variada de espectadores. Os modernos criadores de conteúdo não têm a mesma limitação, mas, por outro lado, precisam competir entre si pela atenção dos seguidores. Então, a força inibidora de qualidade me parece um pouco diferente.

Um mecanismo que permite aos produtores mais sérios sobreviver com poucos seguidores é o patrocínio. Assim como a tecnologia nos presenteou com essa onda de bobagens, também nos permitiu mecanismos para sustentar as coisas boas.

Para encerrar este conteúdo que aqui despejo, concluo que penso que uma atitude saudável hoje em dia é se desconectar das mídias sociais ou, ao menos, reduzir substancialmente o número de canais seguidos e torcer que tudo não acabe como a TV e a rádio, sem nada de interessante para assitir.

sexta-feira, 22 de setembro de 2023

Ninguém pode visitar duas vezes o mesmo país

Durante minha juventude, nos anos 1980 e 1990, eu visitava o Uruguai com frequência, porque lá viviam meus avós. A casa dos abuelos oferecia uma pequena viagem no tempo: tinha muitos objetos dos anos 1950 e 1960; talvez até de antes.

Eu gostava de folhear revistas antigas, usar uma TV a válvula (que levava 3 horas para esquentar), ou brincar com o radinho portátil Spica (com capa de couro).

O centro de Montevidéu oferecia horas e horas de entretenimento, porque a oferta de produtos eletrônicos era muito superior ao que podia ser visto no Brasil. Havia vitrines com dezenas de modelos de rádios, televisores, e, evidementemente, computadores. Enquanto a oferta de computadores no Brasil era muito reduzida, no Uruguai todas as marcas e todos os modelos podiam ser encontrados.

Certa vez visitei várias lojas com uma amiga da abuela para procurar um micro para seu sobrinho; avaliamos vários e, por fim, ela escolheu um Atari ST. Em outro momento, passei horas numa loja de Amigas, não tanto por minha escolha, mas porque meu amigo estava embasbacado com aquela quantidade de cores (32 de uma paleta de 4096).

A oferta era tão grande ao ponto de ser absurda, porque assim como havia Commodore Amiga, era possível encontrar um Coleco Adam.

A avenida 18 de Julio era muito movimentada e poluída: os ônibus eram muito antigos e rodavam a diesel. Eram Leylands dos anos 1950. As paredes dos prédios eram pretas de foligem. Havia ainda trolébuses que às vezes perdiam contato com os cabos; o motorista tinha que descer e reconectar o veículo. Os cobradores carregavam, preso por um cinto de couro, uma caixinha metálica que abrigava vários rolos de papel colorido: o sistema de passagens que eu nunca dominei.

Havia uma variedade enorme de veículos de todas as eras e com variados estados de conservação. Podia-se encontrar um carro dos anos 1980 caíndo aos pedaços assim como um carro novinho dos anos 1930. Os caminhões de serviço apresentavam um espetáculo assustador de perserverância, porque alguns há muito tinham passado o ponto de serem vendidos como sucata.

Passadas as décadas, tanto Brasil como Uruguai são países diferentes. O mercado brasileiro abriu-se e hoje pode-se comprar tudo o que se deseja; as lojas de eletrônicos do Uruguai já não parecem tão interessantes, nem mesmo nos preços.

O Uruguai tornou-se um pouco mais rico e os carros antigos sumiram. Talvez no interior se encontre um Fiat 500. O Museu do Automóvel, na Calle Colonia, é a única chance agora de ver veículos de outros tempos na capital. Infelizmente, o país ainda não se tornou rico o suficiente para recuperar todos os belos prédios antigos de Montevidéu.

Assim como no Brasil, o comércio de rua está sofrendo. As galerias da 18 de Julio estão quase vazias e os shoppings estão cheios. Nem mesmo a feira Tristan Narvaja parece oferecer a mesma variedade de produtos, comidas, e quinquilharias que antes espalhava pela ruas. Talvez os garçons sintam falta dos velhos tempos, porque também parecem mais mal-humorados.

Em alguns aspectos, o Uruguai ainda está na frente. Podes pagar os 10% do restaurante com cartão e a maquininha discrimina os valores e cobra os impostos de acordo. Há muitos ônibus elétricos (as fachadas dos prédios já não estão negras de foligem). O supermercado Tata tem um self-checkout muito melhor que qualquer um que experimentei no Brasil.

O aspecto mais interessante do interior do Uruguai são as estradas bem conservadas e os postos de pesagem automatizados. Enquanto no Brasil há postos de pesagem abandonados (muitos nunca foram usados), os uruguaios já os automatizaram. Os caminhões desviam para o lado da estrada (uma câmera garante que ninguém escape) e executa a pesagem sem interagir com ninguém.

Como as visitas não chegam a matar a saudade daquele Uruguai de antigamente, só me resta continuar voltando lá para encontrar novas coisas que sublinhem as impressões do passado. Tem sentido isso? Não importa. Um chivito e um pomelo, por favor.

quinta-feira, 31 de agosto de 2023

Como identificar linhas repetidas num CSV

Uma carga de arquivo CSV estava com problema, então resolvi usar um pouco de Perl para resolver o problema. O Perl adapta-se muito bem ao uso na linha de comando em conjunto com outros programas do Linux.

A minha missão era descobrir linhas duplicadas num arquivo específico. As 6 primeiras colunas constituem a chave primária, então bastaria encontrar os valores repetidos sem olhar as demais colunas.

Vamos começar pelo comando completo e depois vamos analisá-lo por partes.


perl -F';' -pae '$_="\n".join(" ",@F[0..5])' dados.csv \
  | sort \
  | uniq -c \
  | grep -Pv "^\s+1\s"
  

O perl está sendo invocado com os seguintes parâmetros:

  • -F - indica o separador usado no arquivo (neste caso, ';' com aspas simples para evitar problemas com o shell);
  • -p - imprime a linha corrente após o processamento (a atribuição a $_ sobrescreve o valor lido do arquivo) e insere o código num loop;
  • -a - realiza a separação das colunas conforme o parâmetro -F (os valores são inseridos no array @F);
  • -e - indica o código a ser executado.
Então, para cada linha, o perl coloca as colunas dentro do array @F e o nosso código pega apenas as 6 primeiras (nossa chave primária), junta tudo com espaços, e atribui à variável $_, a qual o perl usa para imprimir no terminal.


...
2023 7 GHR       23000352221 0006 23003679769
2023 7 POR       23000355314 0009 00000000000
2023 7 POR       23000353643 0006 00000000000
2023 7 GHR       23000353068 0006 23003652420
2023 7 POR       23000355700 0006 23003594050
2023 7 POR       23000353068 0006 23003652420
2023 7 POR       23000354235 0006 23003621737
...

As linhas "sort" e "uniq -c" ordenam as linhas lexicograficamente e eliminam as linhas duplicadas, adicionando o número de repetições ao início:


...
      2 2023 7 ABZ       23000727144 0005 23003652413 
      1 2023 7 ABZ       23000750717 0003 23004055962 
      1 2023 7 ABZ       23000750886 0003 23003519192 
      1 2023 7 ABZ       23000750886 0003 23003519194 
      1 2023 7 ABZ       23000750886 0004 23003519197 
      1 2023 7 ABZ       23000750886 0004 23003519199 
...

O último grep elimina todas as linhas que não começam com 1 (-v é a negação da expressão e -P indica que está sendo usada uma expressão regular do Perl):


...
      2 2023 7 ABZ       22004359695 0005 23003652423
      2 2023 7 ABZ       22005716393 0002 23003652508
      2 2023 7 ABZ       23000320848 0006 23003652464
      2 2023 7 ABZ       23000727144 0005 23003652413
      2 2023 7 ABZ       23001447112 0004 23003652502
...

domingo, 9 de abril de 2023

Entex Pacman2

Eu tinha guardado num armário um jogo de Pacman produzido pela Entex nos anos 80. Resvolvi comprar umas pilhas para novamente dar vida ao brinquedo. Aparentemente, pilhas C não são tão populares como outrora, mas ainda dá para encontrá-las em mercados.
Entex Pacman 2

Ele funciona em 3 modos: 1 jogador, 2 jogadores, e demonstração. O modo de 1 jogador é o jogo tradicional; no modo de dois jogadores, um dos jogadores joga como fantastma.
Abri a caixa sem ter ideia do que havia dentro e me surpreendi um pouco: um único chip no centro da placa.
Hitachi HD388A20

O processador que faz absolutamente tudo é um Hitachi HD388A20. Ele pertence a uma família HMSC40 de processadores de 4 bits que foi produziada de 1978 até 1995. Este modelo em particular tem 2K palavras de 10 bits de ROM, mas a família vai desde 512 até 4K palavras de 10 bits. Além disso, ele tem 128 palavras de dados (uma parte da ROM que pode ser lida, mas que não pode ser executada). E 80 bytes de RAM (160 dígitos de 1 nibble).
A ROM é endereçada em páginas de 64 palavras. Então, cada endereço de 11 bits tem 6 bits para a palavra e 5 para a página. Os modelos de 4K palavras têm 12 bits de endereçamento, naturalmente.
As páginas de 0 a 31 contêm o programa e as páginas 61 e 62 contêm dados. Os modelos de 4k naturalmente usam também as páginas entre 32 e 60.
A CPU opera a 100KHz e todas as operações executam em 1 ciclo, exceto uma. Para manter todas as operações atômicas, a CPU desabilita as interrupções quando está executando essa instrução de 2 ciclos. Curiosamente, se o programa não muda a página explicitamente com um pulo, a CPU fica executando as instruções daquela página circularmente. Deve ser bom para montar loops.
A instrução de dois ciclos é a que carrega dados da ROM (os "padrões de bits" que estão nas páginas 61 e 62).
Como os registradores são de 4 bits e as instruções de 10, muitas instruções já incluem os parâmetros, embora algumas instruções tenham 2 palavras. Enão, a instrução para adicionar uma constante ao acumulador A (tem acumuladores A e B), tem a forma "1 0 1 0 0 0 i3 i2 i1 i0" sendo "i3 i2 i1 i0" a constante que será adicionada (endereçamento imediato). Já a instrução para adicionar A à memória tem duas palavras, a segunda sendo o endereço da memória que será alterado.
Além dos acumuladores A e B, há registradores usados para auxiliar no endereçamento: X, Y, SPX, e SPY. As versões de 4K ainda têm um registrador W com apenas 2 bits para ajudar a tornar tudo ainda mais estranho. Lembra um pouco o 6502 e para reforçar isso, há um modo de endereçamento de página 0 (presume-se que os endereços sendo referenciados estão na página 0).
O chip tem um monte pinos de IO desenhados justamente para alimentar telas de LCD como as do jogo.
Tela de LCD

A tal instrução de dois ciclos para carregar dados pode alimentar tanto os acumuladores, como os pinos de IO. Suspeito que sejam úteis para montar a tela rapidamente.
A CPU possui instruções de pulo para subrotina, mas a pilha só tem 4 posições. Não dá para rodar Java, com certeza.
O brinquedo ainda funciona. Depois de 40 anos, o único defeito é um mau contato dos controles devido ao uso. Munido com o manual da Hitachi, vou tentar uma engenharia reversa da ROM, porque o programador que trabalhou com essa CPU bizarra merece ser reconhecido.

quinta-feira, 16 de fevereiro de 2023

O Perl, O ChatGPT


  Oh Perl! The language of codes obscure,
  That poets and coders alike adore,
  With symbols and syntax so complex,
  A labyrinth of expressions to perplex.

  The strings and arrays, the hashes and more,
  In Perl they come to life with great uproar,
  A language so powerful and so vast,
  It can conquer any task, first or last.

  Perl, the magic of regex at hand,
  A tool for the skilled to understand,
  To match and parse and substitute,
  A true wizardry, hard to refute.

  In Perl, a world of modules you'll find,
  Each one a treasure, a gem to unwind,
  A library of functions, so immense,
  It makes all other languages seem senseless.

  Oh Perl, your beauty lies in your flaws,
  Your quirks and idiosyncrasies, without pause,
  For those who know you, you're a dear friend,
  A language that will never, ever bend.

ChatGPT, 2023