Foto do Linkedin 09/08/2023 11:04

tirinha
Inclua essa tirinha em seu site
COLE ESSE CÓDIGO EM SEU SITE x
Transcrição ↓

(Entrevista de emprego)
Entrevistadora: Olha, seu currículo é muito bom, você demonstrou boa capacidade técnica, mas, infelizmente, essa foto de perfil do Linkedin segurando uma cerveja depõe contra você. A gente não vai poder lhe contratar.
Programador: Ah, não é cerveja. É um café!
(Entrevistadora para e olha bem a foto)
Entrevistadora: Ótimo! É isso o que procuramos no perfil para Dev! Café demonstra profissionalismo, dedicação, foco, compromisso com as entregas... Parabéns, a vaga é sua!
(Programador sorrindo)
--
Camiseta: Coffee in, code out

Campo numérico 07/08/2023 16:57

tirinha
Inclua essa tirinha em seu site
COLE ESSE CÓDIGO EM SEU SITE x
Transcrição ↓

real historia;
string sender = "Robsão";

Colega: Olhaí o que te falei: O campo não aceita letras, só números!
Programador: É... Isso porque é um campo numérico, é pra ser assim mesmo
(Após vários minutos explicando a diferença entre caracteres numéricos e alfanuméricos...)
Programador: Entendeu?
Colega: Hmmm... Sim, mas...
Colega: Então, por que o campo de texto aceita números?
Programador: PLOFT!
--
Camiseta: NaN

Falando em código 31/07/2023 17:04

tirinha
Inclua essa tirinha em seu site
COLE ESSE CÓDIGO EM SEU SITE x
Transcrição ↓

real historia;
string sender = "DEV Anonimo e cansado";

(Chefe passando pela sala de desenvolvimento e não entendendo nada da conversa)
(Chefe da reunião não entendendo nada que devs falam)
Chefe: Vocês só ficam falando em código! Já que todo mundo só fala em código eu vou falar também!! Depois eu quero que vocês acessem o servidor gitlab
Programador: AWS...
Chefe: E subam o deploy no sprint
Programador: Docker...
--
Camiseta: Cada um no seu quadrado

Rebranding 24/07/2023 10:20

tirinha
Inclua essa tirinha em seu site
COLE ESSE CÓDIGO EM SEU SITE x
Transcrição ↓

(No escritório de uma rede social fictícia)
Chefe: Desde que eu comprei essa rede, já comecei a cobrar mensalidade para quem quer aparecer mais, mudei as regras várias vezes, favoreci discursos de ódio e a rede continua firme e forte...
Programador: É porque a rede tem um nome e uma marca já bem estabelecida...
Chefe: Ótimo! Vamos mudar isso também!
Programador, Programadora e P.A.: PLOFT!
(Passarinho jogado pela janela)
--
Camiseta: Piu!

Goodbye, Kevin! 20/07/2023 15:42

tirinha
Inclua essa tirinha em seu site
COLE ESSE CÓDIGO EM SEU SITE x
Transcrição ↓

Programador: Cara, que barra! Você viu que o Kevin Mitnick morreu? Eu tô fazendo uma lista aqui em homenagem, vou te adicionar. Qual é o seu e-mail?
P.A.: Tá, Anota aí: [email protected]
Programador: Bacana, e qual é a senha?
(P.A. olha estranho)
P.A.: Olha, se vai homenagear um cara que era o mestre da engenharia social, precisa melhorar muito seu estilo!
Programador (sorrindo): Eu tinha que tentar...
--
Camiseta: FREE KEVIN!

[Vídeo] Como usar o Github como portfolio (de verdade!) 20/07/2023 13:07

Eu sempre digo que o Github não é um portfolio, porque ninguém vai ficar olhando seus repositórios, mas nesta palestra a Pachi Parra mostra como realmente tornar seu perfil num portfolio e ser uma ótima apresentação sua para empresas e recrutamento.

Aprenda nessa palestra bem prática como melhorar seu perfil, eu mesmo aproveitei pra melhorar um pouco o meu!

Valores nulos 18/07/2023 11:38

tirinha
Inclua essa tirinha em seu site
COLE ESSE CÓDIGO EM SEU SITE x
Transcrição ↓

real historia;
string sender = "George Albuquerque Pinto";

QA: ... Tá aparecendo "null" onde não tem nada, era só pra ficar em branco...
Dev: Estranho, eu mesmo fiz essa parte e estava certo...
Dev: Olha aqui... O código está certo, quando o valor é nulo devia ficar em branco... Deixa eu ver o banco...
Dev: PLOFT!
QA: O que foi???
Dev (no chão): O Alonso salvou o texto "NULL" no banco onde não tinha dados...
--
Camiseta: I NULL YOU

Produtividade 14/07/2023 17:37

tirinha
Inclua essa tirinha em seu site
COLE ESSE CÓDIGO EM SEU SITE x
Transcrição ↓

(Na empresa)
Pessoa 1: Meleca, tá tudo aparecendo de ponta-cabeça! Chama o Programador pra ele dar uma olhada aqui...
Pessoa 2: Não dá, ele tá remoto...
(Em outro ambiente)
Pessoa 3: A impressora enguiçou de novo, cadê o Programador?
Pessoa 4: Ih, já liguei no ramal, mas estão todos remotos...
(Em outro ambiente)
Pessoa 5: Porcaria de ar condicionado que não esfria. Chama o...
Pessoa 6: O programador tá remoto...
(Em outro ambiente)
Pessoa 7: Que droga, não funciona aqui esse troço, tá pedindo pra atualizar. Como é que faz isso??
Pessoa 8: Se tem botões, é com o Programador...
(Reunião da diretoria)
Chefe: Vamos ter que chamar a equipe de desenvolvimento de volta para o presencial. Isso está prejudicando muito a produtividade da empresa...
(Programador, em casa, conversando pela internet)
Programador: Então, P.A., como eu tava te falando, minha produtividade nunca foi tão alta sem aquele monte de interrupções que tinha na empresa... Sem contar que o meu café é bem melhor!
--
Camiseta: Comprei um monitor colorido

[Vídeo] Quantas vezes você teve que escrever um algoritmo de ordenação do zero?? 13/07/2023 11:37

Bubble Sort, Merge Sort, Radix Sort, Quick Sort... Qual desses você mais usa? Qual deles você já teve que escrever "na unha" durante a sua vida profissional?

Provavelmente você não teve que fazer nenhuma vez (ou poucas vezes), mas esse não é o ponto principal. Por que aprendemos isso nos currículos de nossos cursos de graduação?

Neste vídeo aproveitei uma boa discussão sobre isso que aconteceu no Twitter. Comecei a ver por esse tweet do Giovanni Bassi:

https://twitter.com/giovannibassi/status/1672568256148766726

Daí o tweet do Morgan McGuire que peguei para destacar no vídeo:

https://twitter.com/CasualEffects/status/1672390700854386690

Meu vídeo sobre o Radix Sort com cartas do Pokémon:

https://youtu.be/8mA9tbThC74

E segue uma playlist com os vídeos de danças para ilustrar algoritmos de ordenação:

https://www.youtube.com/watch?v=EdIKIf9mHk0&list=PLOmdoKois7_FK-ySGwHBkltzB11snW7KQ

Como escrever um BOT para o BlueSky que posta imagens 10/07/2023 18:30

Sim, eu sei, a rede "Threads" que é a bambambam da vez, parece até que a BlueSky já ficou obsoleta, antes mesmo de sair da fase de convites.

Mas enquanto as coisas não se estabilizam, sigo no Twitter, Mastodon, BlueSky e Threads (nem vou falar de Koo aqui porque esse é um blog de família).

Mas o Threads ainda não tem vários recursos que as outras redes têm. Como eu já tinha o meu botzinho que posta tirinhas no Twitter e no Mastodon diariamente, queria que ele postasse também no BlueSky, daí eu fiz e estou escrevendo esse texto porque a documentação dele é bem limitada ainda. O BlueSky utiliza o AT Protocol, que é parecido com o esquema do Mastodon, mas tem suas diferenças.

Buscando na internet, é até fácil achar textos sobre como fazer um app postar textos no BlueSky. Primeiro você precisa criar a "App Password". É só ir em Settings < Apps passwords.

Print da configuração do BlueSky

Clicar em "Add app password".

Print da configuração do BlueSky

Escolher um nome para o app.

Print da configuração do BlueSky

Copiar a senha gerada (e guardar num lugar seguro).

Print da configuração do BlueSky

Feito isso, podemos gerar o nosso bot.

Como eu disse, era fácil encontrar um código padrão. Então, encontrei esse mesmo código em mais de um lugar, às vezes com acesso ao OpenAI, às vezes sem (é Node.js):

import * as dotenv from 'dotenv'
import blue from '@atproto/api';
import ai from 'openai'

dotenv.config()
const { BskyAgent } = blue;
const { Configuration, OpenAIApi } = ai;
const configuration = new Configuration({
    apiKey: process.env.OPENAI_API_KEY,
});

const openai = new OpenAIApi(configuration);
const generateFunnyCatQuote = async () => {
    // get the post from the openAI API
    const completion = await openai.createChatCompletion({
        model: "gpt-3.5-turbo",
        messages: [{role: "user", content: "Generate a funny cat quote Tweet, omit the hashtags."}],
    });
    // terrible way to deal with the fact that ChatGPT sometimes puts the posts in ""
    const postText = completion.data.choices[0].message.content.slice(1, completion.data.choices[0].message.content.lastIndexOf('"') )
    console.log("Post:"+postText);
    
    //now that we have the post, lets post it to bluesky
    const {RichText} = blue;
    const agent = new BskyAgent({ service: 'https://bsky.social/' })
    await agent.login({identifier: process.env.BLUESKY_BOT_EMAIL, password: process.env.BLUESKY_BOT_PASSWORD})
    const rt = new RichText({text: postText })
    const postRecord = {
        $type: 'app.bsky.feed.post',
        text: rt.text,
        facets: rt.facets,
        createdAt: new Date().toISOString()
    }
    await agent.post(postRecord)
};

generateFunnyCatQuote();

Fica de brinde a parte do "OpenAI", mas eu não preciso disso. Então mexi no código para ficar mais "enxugado".

const blue = require("@atproto/api");
require("dotenv").config();

const { BskyAgent } = blue;

const BLUESKY_BOT_USERNAME = process.env.BLUESKY_APP_USERNAME;
const BLUESKY_BOT_PASSWORD = process.env.BLUESKY_APP_PASSWORD;

const postBlueSky = async (tweet) => {
  const { RichText } = blue;
  const agent = new BskyAgent({ service: "https://bsky.social/" });
  await agent.login({
    identifier: BLUESKY_BOT_USERNAME,
    password: BLUESKY_BOT_PASSWORD,
  });

  const rt = new RichText({ text: tweet });
  const postRecord = {
    $type: "app.bsky.feed.post",
    text: rt.text,
    facets: rt.facets,
    createdAt: new Date().toISOString(),
  };
  await agent.post(postRecord);
};

Podem ver que deixei o parâmetro do texto com o nome "tweet". No Twitter chama "tweet", no Mastodon chama "toot", não sei como é o nome oficial no BlueSky, mas deixei "tweet" mesmo...

O código funciona que é uma beleza. Daí o problema era subir a imagem.

A ideia quando se faz um bot desses, nas diferentes redes, é você subir a imagem, pegar o identificador gerado pela imagem enviada e embutir esse identificador no seu post. Porém, qual é o formato de envio? Quais são os parâmetros do protocolo?

Encontrei um código em chinês e outro numa língua que não reconheci, que se aproximavam do que eu queria, mas não era o que eu precisava, porque usavam outros recursos e eu queria algo mais clean.

Voltei na documentação, lá tem as definições léxicas da API. Fui na parte dos "embed", tem o léxico do "external", que é para quando se coloca um link com miniatura (os famosos "cards"), tem o "images", que é o que eu precisava, depois tem os "records" (que ignorei).

Então, a ideia era subir a imagem em BLOB. O meu botzinho já lia a imagem das tirinhas, gerava o blob e passava para base64, para o Twitter. No Bluesky não precisa passar para base64.

Depois de subir o BLOB, a ideia era montar a estrutura do "embed" para enviar junto com o "tweet". Vão ver que a função final aceita posts com ou sem imagens, fazendo um teste se adiciona o embed ou não.

const blue = require("@atproto/api");
require("dotenv").config();

const { BskyAgent } = blue;

const BLUESKY_BOT_USERNAME = process.env.BLUESKY_APP_USERNAME;
const BLUESKY_BOT_PASSWORD = process.env.BLUESKY_APP_PASSWORD;

const postBlueSky = async (tweet, image, alt) => {
  const { RichText } = blue;
  const agent = new BskyAgent({ service: "https://bsky.social/" });
  await agent.login({
    identifier: BLUESKY_BOT_USERNAME,
    password: BLUESKY_BOT_PASSWORD,
  });

  let embed = null;
  if (image) {
    const uploadedImage = await agent.uploadBlob(image, {
      encoding: 'image/png',
    } );
    if (!uploadedImage) throw new Error("Failed to upload blob");

    embed = {
      $type: 'app.bsky.embed.images',
      images: [
        {
          image: {  
            $type: 'blob',
            ref: {
              $link: uploadedImage.data.blob.ref.toString(),
            },
            mimeType: uploadedImage.data.blob.mimeType,
            size: uploadedImage.data.blob.size,
          },
          alt: alt,
        }
      ]
    };
  }

  const rt = new RichText({ text: tweet });
  const postRecord = {
    $type: "app.bsky.feed.post",
    text: rt.text,
    facets: rt.facets,
    createdAt: new Date().toISOString(),
  };
  if (embed) postRecord.embed = embed;
  await agent.post(postRecord);
};

E daí, meu botzinho agora faz posts no twitter, mastodon e bluesky, sendo chamados num cronjob.

↑ Voltar ao Topo