Quantcast
Channel: Paradoxo Final

A regra é clara

$
0
0
"A regra é clara" - Coelho, Arnaldo Cezar.

Antes de começar gostaria de deixar claro que esse texto não é sobre futebol (é muito polêmico). Falarei sobre condomínio, portanto, um assunto muito mais brando. Se bem que o texto abaixo pode ser aplicado em praticamente todas as áreas, como você verá.

Tem gente que não dá bola pras regras, que acha que a percepção dele está correta e não o que está escrito. Para não ir longe demais vou dar um exemplo do que ocorre num condomínio (já adianto que não é o meu).

Digamos que esse sujeito more do 30º andar, e tenha dois elevadores (ia chamar de social e o de serviço, mas hoje em dia o pessoal está tão chato que vou chama-los de A e B). No elevador A você não pode andar com animais de estimação e no elevador B você pode. Não sou eu que disse isso, e sim o regimento interno.

Ele vai levar seu pet (é assim que chamam agora? - sou velho, me processem) para passear, e ao fechar a porta do apartamento, percebe que:
1. O elevador A está parado no 30º andar;
2. O elevador B está no térreo.

Com essas informações nosso amigo toma a decisão mais sensata: vou pelo elevador A, pois assim economizo energia - viu só sou um cara legal!?

Esquece nosso amigo, que quando o regimento interno foi escrito e aprovado, ele deveria ser seguido por todos, sem exceções. E sabe porquê não podem haver exceções, porque elas normalmente são interpretativas. O que eu acho não é o que você acha, ou a mulher do 2501 acha. Posso achar conveniente fazer a mudança de madrugada para não prejudicar o uso do elevador para os demais. Viu só como sou bonzinho!? É justamente para isso que existem as regras.

Em tempo: acho isso uma besteira, mas não vou contrariar o regimento interno.

Dicas de como trabalhar com o Outlook

$
0
0
Trabalho com o Outlook desde 2004, e só agora, em 2019 e 2020, descobri duas dicas bem interessantes de como trabalhar com ele. Na verdade, nem sei se as versões (minha versão é a Professional Plus 2013) mais antigas suportam isso que vou falar, mas creio que sim.

A primeira dica, um colega de trabalho mostrou ano passado e tem a ver com Regras e Alertas e consiste em criar Categorias com cores diferentes, dependentes do encaminhamento da mensagem:

- somente para mim, prioridade alta, cor verde;
- enviada também para mim, prioridade média, cor azul;
- enviada para mim, em cópia, prioridade baixa, cor cinza.



Basta criar uma regra para cada um desses encaminhamentos e sinalizar a categoria desejada. É muito útil para quem recebe dezenas ou centenas de emails diariamente e precisa priorizar a leitura. Dessa forma, uma primeira priorização já é feita automaticamente.

A segunda dica, tem a ver com as pastas de pesquisa. Sabe aquelas pesquisas que você rotineiramente repete? Ao invés de você digitar os critérios todas as vezes, basta clicar na pasta que os resultados já são mostrados. No meu caso, criei três pastas de pesquisa e coloquei como Favoritos. Posteriormente você pode alterar os critérios de pesquisa.

- Para Acompanhento: mostra todas as mensagens marcadas para acompanhamento, não importa a pasta ou sub-pasta onde se encontra.
- Esta Semana: mostra todas as mensagens recebidas esta semana.
- Importante: mostra todas as mensagem marcadas como importante.


Para criar uma pasta de pesquisa, clique com o botão da direita em "Pastas de Pesquisa", clique em "Nova Pasta de Pesquisa"

Depois, selecione um tipo de pasta (pesquisa). Depois você pode personalizar a pasta, clicando nela com o botão da direita.



Coldfusion

$
0
0
Em 2004 tive que aprender uma nova linguagem de programação para o meu trabalho: Coldfusion. Na época eu usava Delphi e Visual Fox Pro e sendo sincero, nunca havia ouvido falar de Coldfusion! Minha sorte que a curva de aprendizado do Coldfusion é extremamente rápida e em pouco tempo já estava dando manutenção e desenvolvendo software em Coldfusion.

Hoje, 16 anos depois, vejo um twitter do Ben Nadel (https://twitter.com/BenNadel/status/1249679353660739585) falando sobre porque gosta de Coldfusion. Não vou falar porque eu gosto de Coldfusion, até porque o Ben fala com mais propriedade que eu, mas não foge muito do que ele disse.

Infelizmente, minha empresa está abandonando o Coldfusion, mas sempre vou ter um carinho especial por essa linguagem.

Concorrência com GO

$
0
0
Comecei a programar com GO há pouco tempo. E logo me deparei com algumas dúvidas de como usar a concorrência. Pesquisei bastante e encontrei algumas soluções muito interessantes, as quais compartilho aqui.

Sugiro você primeiro assistir esse video do Rob Pike no Google I/O 2012: https://www.youtube.com/watch?v=f6kdp27TYZs&t=944s. Os programas que ele mostra podem ser encontrados aqui: https://github.com/kevchn/go-concurrency-patterns. E a apresentação que ele utilizou está aqui: https://talks.golang.org/2012/concurrency.slide

Outros links que li e achei úteis sobre concorrência em GO:

Por fim, criei um exemplo (https://github.com/alexsetta/seqVsConc), no qual comparo o desempenho de duas funções que fazem a mesma coisa: acessar um slice de URLs e retornar o StatusCode de cada uma. A diferença é que uma função faz a busca sequencial e a outra de forma concorrente. 

Na prática, o tempo sequencial é a soma de todos os tempos individuais pois a função acessa uma URL, espera a resposta e segue adiante e o tempo concorrencial é, para um número limitado de URLs, o tempo de acesso da URL mais lenta, pois neste caso a função dispara várias chamadas simultâneas e quando a mais lenta terminar as outras já terão terminado.

O tempo de resposta fala por si só:

package main

import (
"fmt"
"net/http"
"time"
)

// func siteStatusCodeConc(urls ...string) // cria um canal de string
c := make(chan string)

// laço para cada url passada por parâmetro
for _, url := range urls {
// chama uma goroutine que verifica se o site está online ou não
go func(url string) {
resp, err := http.Get(url)
if err != nil {
panic(err)
}
c }(url)
}
return c
}

// func siteStatusCodeSeq(urls ...string) []string{
// cria um slice vazio para retorno
result := make([]string, 0)

// laço para cada url passada por parâmetro
for _, url := range urls {
// chama uma função que verifica se o site está online ou não
resp, err := http.Get(url)
if err != nil {
panic(err)
}
result = append(result, url + " - " + resp.Status)
}
return result
}

func main() {
startTime := time.Now()
resultSeq := siteStatusCodeSeq("https://www.amazon.com", "https://www.correios.com.br","https://www.google.com","https://www.youtube.com")
fmt.Println("Primeiro:", resultSeq[0])
fmt.Println("Segundo:", resultSeq[1])
fmt.Println("Terceiro:", resultSeq[2])
fmt.Println("Quarto:", resultSeq[3])

diff := time.Now().Sub(startTime)
fmt.Printf("Tempo total sequencial: %.2f seconds\n\n", diff.Seconds())

startTime = time.Now()
resultConc := siteStatusCodeConc("https://www.amazon.com", "https://www.correios.com.br","https://www.google.com","https://www.youtube.com")
fmt.Println("Primeiro:", fmt.Println("Segundo:", fmt.Println("Terceiro:", fmt.Println("Quarto:",
diff = time.Now().Sub(startTime)
fmt.Printf("Tempo total concorrente: %.2f seconds\n\n", diff.Seconds())
}

GO: "try/catch" ou "if err != nil"

$
0
0
Assim que comecei a programar em GO, fiquei bastante preocupado pelo fato dele não ter try/catch. Eu já estava (mal) acostumado a usar try/catch em tudo que é lugar. E isso é um erro. Bom, não chega a ser um erro, mas descobri que usar IF de maneira inteligente, o código fica muito mais claro. Como o Rob Pike, diz: "Errors are values".

Além disso, se você tem um bloco de código grande dentro de um try, logicamente terá que tratar todos os possíveis erros dentro do catch, o que visualmente não fica tão claro. Diante disso, passei a não mais encadear um IF dentro de outro (sempre que possível, lógico), e já trato (e retorno) os erros tão logo quanto possível. Parece bobo, mas nem sempre fiz isso. E agora, me parece algo tão óbvio!


Robô para controlar ações e criptomoedas

$
0
0
Uma das vantagens de ser programador é que quando você não encontra o software que quer, você cria um. Eu estava a procura de um robô para me ajudar no controle de ações e criptomoedas, mas não encontrei nenhum gratuito que faz o que eu quero: monitorar a cotação das ações e criptomoedas que eu tenho e me alertar quando eu tiver um determinado ganho ou perda. Queria algo simples e prático. 

Como não achei nada com todas as características necessárias, criei um pra mim. Para isso usei a linguagem Go (Golang). Mas não se assuste, dividi esse post em duas partes: a primeira, uma explicação de como o programa funciona e a segunda, mais técnica. 

A ideia é a seguinte: ler um arquivo com a carteira que eu tenho, com as informações necessárias para me informar quando atingir o valor pré-determinado de ganho ou perda. A cada intervalo de tempo (configurável), carregar as cotações atualizadas da carteira e recalcular tudo novamente. Se ultrapassar o limiar definido de perda ou ganho, informar através de uma mensagem na tela e via Telegram.

Pode parecer que não, mas ajuda bastante: em menos de dois meses, só com Bitcoin, tive um lucro de mais de R$ 1.200,00, investindo pouco mais de R$ 5.000,00. Ou seja, mais de 20% - nada mal...

Exemplo (real) de mensagem enviada pelo programa.

Tudo começa com o arquivo de configuração, que no programa tem o nome de smartbot.cfg:

SleepMinutes: informa o tempo em minutos que o programa deve aguardar para realizar as buscas por novas cotações.
telegramID: é o seu ID no Telegram. Para descobrir qual é, veja aqui: How to get an id to use on Telegram Messenger. Se você não quiser utilizar o Telegram, basta colocar 0 (zero) neste campo.
telegramToken: é o token do bot do Telegram que irá receber as mensagens de alerta. Existem diversos tutoriais ensinando a fazer isso, como 10 Passos para se criar um Bot no Telegram.

Em seguida, configuramos o arquivo carteira.cfg com as informações que formam a nossa carteira de investimentos:

simbolo: apenas o símbolo do ativo
link: link utilizado pelo programa para carregar a cotação*
tipo: tipo do ativo: acao ou criptomoeda
quantidade: quantidade inicial do ativo
inicial: valor inicial pago pelo ativo (unitário)
perda: limite de perda aceitável (em R$)
ganho: limite de ganho desejável (em R$)

* Estou usando o site https://br.investing.com/. No download abaixo, disponibilizo também o meu arquivo carteira.cfg.

Você pode fazer o download do programa executável aqui. Basta descompactar e preencher os arquivos .CFG com as informações necessárias conforme explicado acima. Se tiver alguma dúvida no preenchimento, entre em contato.

A partir daqui vou dar algumas explicações mais técnicas, portanto, se for caso, pode parar de ler.

Com isso definido, podemos iniciar o programa propriamente dito. Inicialmente, defino um struct para os dados de configuração:
type Config struct {
SleepMinutes  int    `json:"sleepMinutes"`
TelegramID    int64  `json:"telegramID"`
TelegramToken string `json:"telegramToken"`
}

E outro struct para os dados da carteira:
type Quotes struct {
Quotes []Quote `json:"quotes"`
}

type Quote struct {
Symbol string `json:"symbol"`
Quantity int64 `json:"quantity"`
Stop float64 `json:"stop"`
}

type Carteira struct {
Ativos []Ativo `json:"ativos"`
}
type Ativo struct {
Simbolo string `json:"simbolo"`
Link string `json:"link"`
Tipo string `json:"tipo"`
Quantidade float64 `json:"quantidade"`
Inicial float64 `json:"inicial"`
Perda float64 `json:"perda"`
Ganho float64 `json:"ganho"`
}

Para ler as configurações dos arquivos CFG, criei uma função:
func readConfig(fileName string, cfg interface{}) error {
b, err := ioutil.ReadFile(fileName)
if err != nil {
return fmt.Errorf("readConfig: %w", err)
}
reader := strings.NewReader(string(b))
if err := json.NewDecoder(reader).Decode(&cfg); err != nil {
return fmt.Errorf("readConfig: %w", err)
}
return nil
}

Entrando no programa principal, carrego o arquivo de configuração:
if err := readConfig("./smartBot.cfg", &config); err != nil {
log.Fatal(err)
}

E finalmente, temos o laço principal do programa, onde primeiramente carrego as informações da carteira e indico se o mercado está aberto (o horário de funcionamento é das 10:00 às 17:30), então, para cada um dos meus ativos, carrego sua cotação e realizo os cálculos para verificar se o limiar de perda ou ganho foi atingido.
for {
	if err := readConfig("./carteira.cfg", &carteira); err != nil {
log.Fatal(err)
}
fmt.Println(time.Now().In(loc).Format("02/01/2006 15:04:05"))
aberto := true
hm := time.Now().In(loc).Format("15:04")
if hm > "17:30" || hm < "10:00" {
aberto = false
}
ultimo := ""
for _, ativo := range carteira.Ativos {
resp, err := calculo(ativo, config)
if err != nil {
log.Println(err)
continue
}
if !aberto && ativo.Tipo == "acao"&& !(hm >= "17:30"&& hm <= "17:34") {
resp += " Mercado fechado"
}
fmt.Println(resp)
ultimo += resp + "\n"
}
ioutil.WriteFile(filename, []byte(ultimo), 0644)
fmt.Println()
if *runonce {
os.Exit(0)
}
time.Sleep(time.Duration(config.SleepMinutes) * time.Minute)
}

A função valor, carrega o link definido no ativo da carteira, lê seus dados, e procura pelo valor da cotação, com a expressão regular definida no programa. Se encontra, remove a formatação da moeda da página e transforma em float64.
var re = regexp.MustCompile(`<span class="arial_26 inlineblock pid-(\d*)-last" id="last_last" dir="ltr">(.*?)</span>`)

func valor(ativo Ativo) (float64, error) {
res, err := http.Get(ativo.Link)
if err != nil {
return 0, fmt.Errorf("valor: %w", err)
}
b, err := ioutil.ReadAll(res.Body)
if err != nil {
return 0, fmt.Errorf("valor: %w", err)
}
doc := string(b)
matches := re.FindStringSubmatch(doc)
if len(matches) != 3 {
return 0, fmt.Errorf("valor: cotação não encontrada: %s", ativo.Simbolo)
}

s := matches[2]
ponto := strings.Index(s, ".")
virgula := strings.Index(s, ",")
//fmt.Printf("DEBUG: %s %d %d\n", s, ponto, virgula)

if ponto < virgula {
if strings.Contains(s, ",") {
s = strings.ReplaceAll(s, ".", "")
}
}
s = strings.ReplaceAll(s, ",", ".")
price, err := strconv.ParseFloat(s, 64)
if err != nil {
return 0, fmt.Errorf("valor: %w", err)
}

return price, nil
}


De posse dos dados retornados pela função valor, a função calculo, faz os cálculos para verificar se  houve o ganho ou perda configurado no ativo.
func calculo(ativo Ativo, cfg Config) (string, error) {
price, err := valor(ativo)
if err != nil {
return "", fmt.Errorf("calculo: %w", err)
}

base := ativo.Quantidade * ativo.Inicial
atual := ativo.Quantidade * price
diff := atual - base

res := fmt.Sprintf("%-12v %-17v %-17v", ativo.Simbolo, fmt.Sprintf("Preço: %.2f", price), fmt.Sprintf("Saldo: %.2f", diff))

if diff < 0 && math.Abs(diff) > ativo.Perda {
msg := fmt.Sprintf(res + "Atingiu o limite de perda!")
sendTelegram(cfg, msg)
return msg, nil
}

if diff > 0 && diff > ativo.Ganho {
msg := fmt.Sprintf(res + "Atingiu o limite de ganho!")
sendTelegram(cfg, msg)
return msg, nil
}

hm := time.Now().In(loc).Format("15:04")
if hm >= "10:00"&& hm <= "10:04" {
msg := fmt.Sprintf(res + "Abertura do mercado")
//sendTelegram(cfg, msg)
return msg, nil
}

if hm >= "17:30"&& hm <= "17:34" {
msg := fmt.Sprintf(res + "Fechamento do mercado")
//sendTelegram(cfg, msg)
return msg, nil
}

return res, nil
}

O código completo do programa pode ser baixado no Github.

Dica rápida: compartilhar por Telegram (mensagens salvas)

$
0
0

Uso o Telegram há bastante tempo, mas só recentemente descobri (mais) uma utilidade: uso ele para compartilhar páginas, artigos, tweets, etc. É só enviar para o grupo "Mensagens Salvas". 

Por exemplo: no Twitter, você seleciona "Compartilhar Tweet por...", escolha "Telegram":

 e depois o grupo "Mensagens Salvas":



A era dos serviços

$
0
0

 Já repararam na enorme quantidade de serviços que assinamos? Vou começar pelo básico e caso seja necessário, explico o que ele faz:

1. Internet  

2. TV a cabo: sei que a tendência é desaparecer, mas por enquanto ainda pago

3. Telefone fixo: vide acima

4. Celular

Bom, hoje em dia, tem mais alguns que podem ser considerados básicos:

5. Netflix

6. Amazon Prime

7. Disney +

8. Spotify

Continuando, com os "esportivos":

9. Surfview: mostra as condições do mar de determinada praia/pico. 

10.  Sócio torcedor: sou Figueirense sim (não importa se for série A, B ou C), e não tenho vergonha! Deixe sua piadinha aqui, mas lembre-se que o mundo dá voltas, então...

Por fim,

11. Youtube Premium: não suporto as propagandas

12. Google One: desde cedo aprendi que o backup é importante.

13. XBox Gold Live: quem não gosta de um joguinho de vez em quando?

14. Digital Ocean: provedor de infraestrutura na nuvem. Básico para qualquer desenvolvedor.

 Acho que é isso. Imagino que a pelo uns 7 ou 8, a grande maioria assine! Ou estou enganado?


Como ocultar as curtidas de outras pessoas no Twitter

$
0
0

Isso estava me incomodando, pois de uns tempos pra cá, começaram a pipocar diversas curtidas na minha timeline que não me interessavam. Depois de extensa pesquisa (ok, 5 minutos googleando), acho que descobri uma maneira. Segue o passo a passo:

Entre no Twitter, clique em "Mais..." e depois em "Configurações e privacidade".


Em seguida, clique em "Privacidade e segurança", e "Silenciar e bloquear":


Finalmente, clique em "Palavras silenciadas":


Agora basta clicar no sinal de "+", no alto à direita e colocar as seguintes palavras (uma a uma): suggested_liked_tweet e suggest_activity_tweet:

Observações:

1. Opcionalmente, para acessar diretamente a tela de "Palavras silenciadas", basta clicar no link:  https://twitter.com/settings/muted_keywords

2. No celular, muda um pouco, mas a ideia é a mesma: Menu de configurações > Configurações e privacidade > Privacidade e segurança > Palavras silenciadas

Google Hacking

$
0
0

Segurança digital

Quando vemos um ataque a um grande site pensamos que o hacker provavelmente utilizou ferramentas sofisticadas, etc. O que nem todo mundo sabe é que muitas vezes facilitamos tanto o ataque que o hacker só precisa fazer uma pesquisa no Google para descobrir como invadir.

Antes de prosseguir, uma explicação: o Google consegue trazer tantos resultados (incluindo login e senhas) porque seus robôs (também chamados de spiders ou webcrawlers) vasculham constantemente a internet e indexam as páginas. O problema ocorre quando alguém deixa um arquivo TXT com as senhas utilizadas no desenvolvimento do site, por exemplo, e o site está permitindo a indexação desses arquivos. Isso é mais comum do que você imagina, conforme iremos ver mais abaixo.

Esclarecimentos

Não é meu intuito ensinar ninguém a fazer algo ilegal, pelo contrário, o objetivo é dar ferramentas para que você descubra as fraquezas do seu site e dessa maneira, possa fazer os ajustes necessários para diminuir as vulnerabilidades.

O uso indevido é de sua total responsabilidade. Tenha ética!

Google Hacking ou "Pesquisa avançada do Google"

A barra de pesquisa do Google suporta algumas palavras chaves, chamados operadores ou dorks, que permitem você refinar sua pesquisa. Google Hacking é a pesquisa direcionada a encontrar brechas, utilizando esses operadores.

Nem é necessário se aprofundar muito, com somente 3 operadores você já obtém alguns resultados muito interessantes:

    site:           realiza a pesquisa num site específico. Exemplo: site:br
    filetype:    pesquisa somente pelo tipo de arquivo. Exemplo: filetype:txt
    intext:       pesquisa pelo texto especificado. Exemplo: intext:password

Juntando tudo:
Reparem que trouxe 3.690 resultados. São páginas do Brasil (site:br), com arquivos TXT (filetype:txt) e que contém o texto "password" (intext:password)

Por questão de ética vou mostrar só o resultado de 2 páginas, escondendo as informações principais.
Somente nesse arquivo acima, temos 293 emails e senhas.
Já neste site, temos senhas do banco de dados, do FTP, entre outras.

Existe até mesmo um banco de dados dos operadores do Google Hacking: https://www.exploit-db.com/google-hacking-database. Aqui você encontra as pesquisas já prontas, bastando clicar nos links apropriados.

Se isso não é o suficiente para convencer que o  Google Hacking é muito poderoso, que tal essa imagem, capturada de uma câmera num oficina qualquer? Dica: apenas usei o operador intitle: e informei o modelo da camera. Mesmo que solicite senha, existe uma boa chance da senha ser a default, portanto, bastaria uma busca pelo manual da câmera para descobrir qual o login/senha padrões.

Para saber mais:


Como aprender a programar

$
0
0

Estava assistindo um vídeo do Fabio Akita, "A Dor de Aprender | Que Cursos/Livros" e em determinado momento, ele falou sobre os microcomputadores antigos, da década de 80, como o TK95. E logo depois ele pergunta: "Como pessoas como eu, quando criança, conseguimos aprender a programar num ambiente muito mais hostil do que hoje em dia?". Isso me fez lembrar do meu início como programador, em 1985, mesmo ano que comecei a surfar. Já explico o que o surfe tem a ver com isso.

Como ele mesmo diz, naquela época as máquinas eram extremamente limitadas. Perto de agora, a situação realmente não era fácil: não existia internet, poucos livros e cursos, e principalmente não existia o Github. No máximo, algumas revistas como Micro Hobby e Micro Sistemas. 


O meu primeiro computador foi um TK2000 e ele vinha com um manual que ensinava o básico do Basic (isso soou estranho). Meu pai também sabia um pouquinho: ele criou um programa que escolhia um número aleatório e você tentava adivinhar qual era o número, com base no retorno do programa, que informava se o número que você digitou era maior ou menor que o escolhido. 

E como eu consegui aprender? Basicamente não tive muita opção: tentativa e erro. Eu vejo aprender a programar como aprender a surfar. Sei disso porque aprendi as duas coisas na mesma idade e minha base, nas duas situações era a mesma: eu gostava mas não sabia nada antes de começar. Para aprender a surfar, não tem jeito, você vai cair. Faz parte do processo. Em programação é a mesma coisa. O fato de você ficar de pé na prancha, não quer dizer que você surfa. Em seguida novos desafios surgem e você começa a aprender algumas manobras, a dropar ondas maiores.

Com o tempo você passa a dominar a linguagem e começa a aprender outras. No meu caso, depois do Basic, passei para o Assembler 6502. Com isso consegui fazer alguns projetos bem interessantes, como o contador de voltas para meu autorama. Eu desmontei um joystick, e deixei o fio no meio da pista. Assim toda vez que o carrinho passava pelo local, contabiliza as voltas e dava a velocidade média. Isso fez muito sucesso entre meus amigos.

Programa Assembler para produzir som no TK 2000

Cansei de ver a pessoa que recém fez um curso de programação falar algo do gênero: "Agora vou pegar um projeto do zero que é mais fácil". Como você espera criar um projeto do zero se nem conhece a linguagem direito? Hoje em dia temos o Github com milhares de exemplos de bons códigos. Baixe, entenda, modifique, enfim: tente, quando errar, aprenda e tente de novo. Não tem jeito, não é fácil. No pain, no gain.

Mas depois que você aprende uma linguagem é muito mais fácil aprender outra: já programei ou programo em 17 linguagens. Diria que é ordens de grandeza mais fácil depois que você já programa. Mas atenção: eu disse aprender e não se tornar um especialista.

No meu caso, há uns 2 anos comecei a aprender Go porque um colega de trabalho comentou alguma coisa sobre concorrência em Go. Me interessei e resolvi me aprofundar no assunto por conta própria. Alguns meses depois, participei de uma reunião e soube que a empresa tinha interesse em migrar alguns sistemas (ou parte deles) para Go. Como eu já conhecia a linguagem, fui chamado para o projeto.

Se eu puder dar uma dica: programar é ser autodidata. Além disso, é preciso estar sempre se atualizando, comprando livros e estudando.

Saiba mais:

https://www.akitaonrails.com/2019/10/23/akitando-65-a-dor-de-aprender-que-cursos-livros

https://www.paradoxofinal.com.br/2017/06/faca-o-simples.html

https://www.paradoxofinal.com.br/2012/08/computador-na-sala-de-aula.html

https://www.paradoxofinal.com.br/2011/04/para-quem-nunca-viu-um.html

Dica rápida em Golang - blank identifier

$
0
0

Se você está usando o pacote database/sql com mysql e recebe a mensagem "Commands out of sync. Did you run multiple statements at once?", verifique se você não está usando um "blank identifier" no retorno da função "Query", por exemplo.

_, err := db.Query("...")

nesse caso, basta pegar o primeiro retorno (rows) e chamar o método Close()

rows, err := db.Query("...")     
defer rows.Close()

Huguinho, surfe e tubarões

$
0
0

Certa vez, após voltar da Oktoberfest, Huguinho decidiu surfar para curar a ressaca, pois todos sabem que Coca-Cola não cura ressaca: Huguinho, Oktober e Coca-Cola. 

Só que aquele dia, o mar estava grande e quebrando bem longe da areia. 

Talvez não estivesse tão grande...

Depois de pegar algumas (boas) ondas, Huguinho vai um pouco mais para outside para descansar um pouco. Não demorou muito e apareceram vários golfinhos em sua volta. 

O que era

Mas na hora, ainda meio grogue, a centenas de metros da areia, sozinho na imensidão do oceano, ele achou que fossem tubarões. 

Até hoje não se sabe de ninguém que saiu tão rápido da água!

O que Huguinho achou que era


O dia que o Australian Crawl chegou à Balneário Camboriú

$
0
0

Já falei um pouco do Australian Crawlaqui. O que não contei é que fui um dos primeiros a ouvir a banda em Balneário Camboriú. Como diz o Lito, do Aviões e Músicas: "Senta que lá vem história" (pequena, mas é uma história). 

Estamos falando do início dos anos 80, e naquela época para ouvir alguma música nova, era só através de fitas. E eu dia, na casa de um primo de Florianópolis, ouvi essa banda. Claro que fiz uma cópia. Mas gostei tanto que fui atrás da história de como ela chegou no Brasil: um amigo dele tinha ido à Indonésia e parece que ele conseguiu através de um australiano que estava ou morava lá. Não sei se é verdade ou não, mas é o que me contaram. 

Quando voltei para casa, em Balneário Camboriú, passei a ouvir a fita diariamente (e várias vezes ao dia). E não deu outra: alguns amigos ouviram, gostaram, copiaram e daí viralizou.

Tinha um amigo que falava: "Xande, tu é o primeiro cara que ouviu Australian aqui!".





Upload com PHP+JQUERY em AJAX e na mesma página

$
0
0

Se você já perdeu horas procurando um código em PHP que funcionasse para fazer o upload de imagens mas que fizesse isso com AJAX e ainda por cima na mesma página, espero que esse post te ajude!

Crie uma pasta para armazenar as imagens que aqui chamo de upload. Copie e cole o código abaixo (testado com XAMPP localmente):

<?php
if(isset($_FILES['file']['name'])){
   /* Pega o nome do arquivo*/
   $filename = $_FILES['file']['name'];
   /* Local onde sera salvo o arquivo*/
   $location = "upload/".$filename;
   $imageFileType = pathinfo($location,PATHINFO_EXTENSION);
   $imageFileType = strtolower($imageFileType);
   /* Extensoes validas */
   $valid_extensions = array("jpg","jpeg","png");
   /* Checa a extensao do arquivo */
   if(in_array(strtolower($imageFileType), $valid_extensions)) {
      /* Faz o upload */
      move_uploaded_file($_FILES['file']['tmp_name'],$location);
   }
}
?>
<form id="data" method="post" enctype="multipart/form-data">
    <input type="text" name="nome" value="Maria" />    
    <input type="file" name="file" />
    <button>Enviar</button>
</form>
<script>
$("form#data").submit(function(e) {
    e.preventDefault();    
    var formData = new FormData(this);
    $.ajax({
        url: window.location.pathname,
        type: 'POST',
        data: formData,
        success: function(response){
    alert('Upload realizado!');
},
        cache: false,
        contentType: false,
        processData: false
    });
});
</script>

Iniciando o Windows Terminal com layout pré-definido (4 janelas)

$
0
0

Se você gosta ou precisa usar o Windows Terminal (WT), talvez já tenha sentido a necessidade de abrir várias abas. Mas dependendo do que você faz, várias abas não são assim tão confortáveis para trabalhar, . Por exemplo: você sobe um servidor numa aba e em outro dispara comandos CURL para verificar se sua API está respondendo a contento. Nesse caso, você precisa ficar alternando entre as abas para ver o resultado. E se desse para ver tudo de uma só vez? 


O melhor é que dá sim. E é fácil! Basicamente, você chama o executável do WT (wt.exe) passando alguns argumentos. Nesse link, tem uma descrição completa dos argumentos. Uma janela como a de cima, pode ser obtida com o comando:

wt.exe -M -d d:\temp ; sp wsl.exe ~ ; mf left ; sp -d d:\dev ; mf right; sp -d d:\bin\monitor

Uma breve descrição dos argumentos utilizados acima:

-M maximiza a tela
-d abre a janela em um determinado diretório
sp (split-panel) divide uma janela/painel
mf (move-focus) move o foco numa direção (left, right, down, up)

E se eu quiser executar um programa, automaticamente, quando abrir as janelas? Sem problemas! Depois da pasta, acrescente seu comando, após um "cmd /k". Por exemplo: para mostrar o conteúdo do arquivo monitor.log, assim que carregar a tela, na aba da direita em baixo, basta acrescentar: "cmd /k type monitor.log". 

Dessa forma, o comando completo fica assim:

wt.exe -M -d d:\temp ; sp wsl.exe ~ ; mf left ; sp -d d:\dev ; mf right; sp -d d:\bin\monitor cmd /k type monitor.log

Para ficar melhor ainda, crie um atalho no Desktop, apontando para o comando acima e atribua um atalho. ;)



Dicas Go - #1 - Goroutines

$
0
0
Já falei um pouco sobre concorrência em Go, mas percebi que não fui muito esclarecedor, por isso vou fazer uma outra abordagem, mais detalhada, sobre esse assunto. O código completo dos programas está no final do texto.

Vamos imaginar que você queira fazer um programa que faça acesso à uma API algumas vezes e retorne o resultado como string. Para não tornar o programa muito complexo, utilizei uma pesquisa fake, que simula um retorno e gasta  100 milissegundos. Ao rodar o programa sequencial.go, vemos na tela uma saída como a abaixo:


Como esperado, os resultados são listados em ordem, de "golang 0"à "golang 19". E o tempo gasto, pouco mais de 2s, também não é nenhuma surpresa (20 vezes 100 milissegundos mais algum tempo do resto do código).

A coisa começa a melhorar quando rodamos o programa concorrente.go.


O tempo gasto reduziu de 2s para 100ms. Qual é a mágica? São as goroutines! Se reparar bem, são poucas mudanças em relação ao código original (na verdade, essa é uma das formas que podemos usar as goroutines, mas é a que acho mais simples).

A primeira mudança é a criação de um canal com buffer de capacidade 4. Na prática, podemos enviar até 4 valores neste canal sem bloquear a goroutine. 

c := make(chanstring, 4)

A segunda mudança é a chamada da função fakeSearch:

gofunc(j int) {
c <- fakeSearch("golang " + fmt.Sprintf("%d", j))
}(i)

Usamos uma função anônima para englobar a chamada em si, pois esta retorna um canal de string e não temos como chamar a função da forma abaixo:

go c <- fakeSearch("golang " + fmt.Sprintf("%d", j))

Por fim, temos que ler as respostas do canal, e para isso usamos um for para ler cada uma das respostas:

fori := 0; i < 20; i++ {
fmt.Printf("#%d - %s", i, <-c)
}

Aqui, o programa simplesmente joga o resultado que está no canal (<-c) para a tela, mas ele poderia ser armazenado num slice de strings por exemplo.

Código dos programas

Como traduzir (legendar) qualquer vídeo do Youtube

$
0
0

Às vezes você encontra um vídeo no Youtube com a solução do seu problema, mas ele está em uma língua que você não domina. Normalmente, você olha se tem legenda, e na maioria dos casos ou não tem, ou só tem na própria língua do vídeo


Aí você abandona o caso, certo?

O que muita gente não sabe é que o próprio Youtube permite você legendar em qualquer língua (que ele tenha disponível).  O segredo é clicar em Legendas primeiro, e depois em Configurações. Assim, aparecerá a opção "Traduzir automaticamente". Ao clicar nessa opção, basta escolher o idioma da tradução.

Clique no ícone Legendas e no item de menu Legendas

Clique em Traduzir automaticamente

Selecione o idioma

Voilá!

Infelizmente se você fechar o vídeo será preciso executar o processo novamente.

Paradoxo Final: sem anúncios

$
0
0

Quando comecei o blog, em 2009, nunca pensei em ganhar dinheiro. Mas como alguns posts fizeram sucesso e tive meses que alcancei mais de 34 mil visualizações, o dinheiro começou a entrar. Quer dizer, os trocados, pois em 13 anos ganhei menos de 130 dólares. 

De todo modo, em virtude disso, mantive os anúncios. E como somos acomodados por natureza, e mesmo o blog tendo muito menos visualizações, mantive os anúncios.

Mas esse final de semana resolvi removê-los, afinal, não escrevo para ganhar dinheiro (até que gostaria, mas não tenho tempo), escrevo porque eu gosto.

Então, espero que aproveitem a nova cara do Paradoxo Final.

VSCode não roda?

$
0
0

Esses dias fiz uma atualização do VSCode (gosto de manter os softwares atualizados) e ele simplesmente não abriu mais. Clicava no ícone e ele abria e já fechava em seguida.

Depois de muita pesquisa, não descobri o problema. Daí comecei a operar em modo desespero:

Primeiro, tentei acessar sem nenhum extensão, pois imaginei que poderia ser um problema de compatibilidade de uma extensão com a nova versão do VSCode. Para isso rodei o comando:

code --disable-extensions


E nada. Ele simplesmente não dava sinal de vida. Em tempo: se precisar desinstalar uma extensão problemática via linha de comando use:

code --uninstall-extersion <ext-id>


O <ext-id> você consegue com o comando:

code --list-extensions


Depois, tentei baixar versões mais antigas, mas também não adiantou.

https://code.visualstudio.com/updates


Nessas horas a experiência conta muito: resolvi renomear o arquivo settings.json, e deu certo. Ele estava corrompido. Daí foi fácil descobrir o problema do arquivo e corrigir. Esse arquivo fica armazenado em %appdata%\Code\User.


Falha ao acessar a API da Binance

$
0
0

De uns tempos pra cá, meu programa que monitora o preço de ações e criptomoedas (tenho um post sobre isso), passou a receber a mensagem: 

"Service unavailable from a restricted location according to 'b. Eligibility' in https://www.binance.com/en/terms. Please contact customer service if you believe you received this message in error." 

Depois de muito pesquisar, descobri o problema: meu programa fica hospedado nos EUA, e eu uso o endereço base https://api.binance.com. A solução é bem simples, troque o endereço base por https://api.binance.us. O único porém é que alguns assets não existem no novo endereço. Por exemplo: https://api.binance.us/api/v3/ticker/24hr?symbol=ETHBRL. Nesse caso, a única solução é trocar o ETHBRL por ETHUSD.


Dica rápida: .gitignore não "funciona"

$
0
0

Caso você tenha um arquivo que já estava versionado, e você agora quer removê-lo do versionamento, é necessário limpar o cache local do repositório. Para isso basta executar:

git rm -r --cached <path_e_nome_arquivo>


Atual Momento da IA: ChatGPT

$
0
0

A inteligência artificial é um tema que vem ganhando cada vez mais espaço na nossa sociedade e tem a capacidade de mudar a forma como vivemos e trabalhamos. Atualmente, estamos testemunhando um marco na evolução da IA, com modelos como o ChatGPT liderando o caminho.

O ChatGPT é um modelo de linguagem de ponta desenvolvido pela OpenAI. Ele foi treinado em milhões de páginas da web e possui uma incrível capacidade de compreender e gerar texto natural. Isso significa que ele pode responder a perguntas, escrever textos e até mesmo criar conversas com humanos, sem que eles percebam a diferença.

O sucesso do ChatGPT é resultado de anos de pesquisa e desenvolvimento, e ele está mudando a forma como vemos a inteligência artificial. Antes, modelos de IA eram incapazes de compreender o significado por trás das palavras e apenas respondiam com base em padrões previamente programados. Agora, com o ChatGPT, a IA tem a capacidade de aprender e evoluir ao longo do tempo, tornando-se cada vez mais humana.

Além disso, o ChatGPT tem uma ampla gama de aplicações, desde assistentes virtuais até criação de conteúdo. Isso significa que ele pode ser usado para resolver problemas complexos e ajudar a aumentar a eficiência em muitos setores, incluindo saúde, educação e tecnologia.

No entanto, é importante destacar que a inteligência artificial também apresenta desafios éticos e morais. A IA tem o potencial de revolucionar a nossa sociedade, mas também pode ser usada para fins negativos, como monitoramento excessivo e controle governamental. É crucial que continuemos a discutir e a regulamentar o uso da IA, a fim de garantir que seja utilizada de maneira ética e responsável.

Em conclusão, o ChatGPT é apenas o começo da evolução da IA, e estamos empolgados em ver o que o futuro nos reserva. Ele representa um avanço significativo na compreensão da linguagem humana e pode revolucionar muitos aspectos da nossa vida. No entanto, é importante estarmos atentos aos desafios éticos e regulamentarmos o uso da IA para garantir que seja usada de maneira responsável e benéfica para todos. 

(lógico que o artigo foi escrito pelo ChatGPT)

ABS (Arquitetura do Bom Senso): A Importância do Bom Senso na Arquitetura de Software

$
0
0

Durante as últimas semanas acompanhei algumas discussões sobre arquitetura de software e clean code. Por isso resolvi escrever esse artigo.

A arquitetura de software é fundamental no desenvolvimento de sistemas de alta qualidade e desempenho. É responsável por definir a estrutura e organização do código-fonte, as interações entre os diferentes componentes e as diretrizes para garantir a escalabilidade, manutenibilidade e extensibilidade do sistema. No entanto, além de técnicas e padrões estabelecidos, existe um fator crucial que muitas vezes é negligenciado: o bom senso. Neste artigo, exploraremos a importância do bom senso na arquitetura de software, apresentando a ideia da ABS (Arquitetura do Bom Senso) e como ela pode impactar positivamente os projetos de desenvolvimento.

O que é a ABS (Arquitetura do Bom Senso)?

A ABS (Arquitetura do Bom Senso) é uma abordagem que destaca a importância de aplicar o bom senso durante o processo de arquitetura de software. Ela reconhece que as melhores práticas e diretrizes estabelecidas são importantes, mas também ressalta a necessidade de considerar o contexto específico do projeto, as necessidades dos usuários e as restrições impostas pelo ambiente.

Por que o bom senso é importante na arquitetura de software?

  • Contextualização do projeto: Cada projeto possui requisitos, restrições e objetivos específicos. O bom senso permite avaliar esses elementos e adaptar a arquitetura para atender às necessidades do projeto de forma eficiente. Não existe uma solução única para todos os casos, e o bom senso nos ajuda a encontrar o equilíbrio certo.
  • Usabilidade e experiência do usuário: Uma boa arquitetura de software deve priorizar a usabilidade e a experiência do usuário. O bom senso nos permite analisar as interações entre os diferentes componentes do sistema e tomar decisões que melhorem a navegabilidade, a eficiência e a intuitividade da aplicação.
  • Escalabilidade e manutenibilidade: O bom senso também é essencial para garantir que a arquitetura seja escalável e de fácil manutenção. Isso envolve a escolha de padrões e abordagens que facilitem a adição de novos recursos e a correção de problemas sem comprometer a estabilidade do sistema.

Diretrizes para aplicar a ABS (Arquitetura do Bom Senso):

  • Conheça o contexto: Compreenda os requisitos, restrições e objetivos do projeto, bem como as expectativas dos usuários. Isso ajudará a moldar uma arquitetura adequada ao ambiente específico.
  • Avalie as melhores práticas: Familiarize-se com as melhores práticas e diretrizes estabelecidas na área de arquitetura de software. Entenda seus benefícios e limitações para aplicá-los de forma adequada.
  • Analise os trade-offs: Reconheça que nem sempre é possível atender a todos os requisitos de forma ideal. É necessário analisar os trade-offs e tomar decisões embasadas no contexto e nas necessidades do projeto.
  • Mantenha a simplicidade: Busque soluções simples e elegantes. Evite a complexidade desnecessária, pois isso pode dificultar a compreensão, manutenção e evolução do sistema.
  • Adapte-se às mudanças: Esteja aberto a mudanças e atualizações na arquitetura à medida que o projeto evolui. O bom senso exige flexibilidade e adaptação às novas circunstâncias.

A arquitetura de software é uma disciplina que envolve conhecimento técnico, padrões estabelecidos e melhores práticas. No entanto, a aplicação do bom senso é o fator crucial que pode diferenciar um sistema bem-sucedido de um que falha em atender às expectativas. A ABS (Arquitetura do Bom Senso) destaca a importância de considerar o contexto, as necessidades dos usuários e as restrições impostas pelo ambiente. Ao aplicar o bom senso, os arquitetos de software podem tomar decisões mais embasadas, resultando em sistemas mais eficientes, escaláveis e fáceis de manter. Portanto, não subestime o poder do bom senso na arquitetura de software - ele pode ser o elemento chave para o sucesso do seu projeto.

Sugiro a leitura do artigo Curiosity e suas 2,5 milhões de linhas de código, principalmente a parte onde mostro as regras de programação da JPL/Nasa. 






A incrível velocidade do Go

$
0
0

Um dos motivos que gosto do Go (a linguagem de programação, não o jogo), é que ele é extremamente rápido. E não estou falando de utilizar goroutines pois aí é covardia.

Estamos migrando um sistema de Coldfusion para Go e PHP e uma das rotinas insere um registro no banco de dados no início e outra no fim do processo. Pense como se fosse um log, mas um log específico para essa rotina. Dessa forma:

2023-05-18 17:45:03.687    ... [processaImagem] Incorporando imagem
2023-05-18 17:45:03.688    ... [processaImagem] Imagem incorporada

Entre o inicio e o final do processamento levou 1ms. Até aí, tudo bem, se não fosse o fato dessa tabela ter o campo timestamp como parte da chave primária. Se reparar, o tempo é definido em milissegundos. Com o Coldfusion esse processo dura cerca de 20ms. Simplesmente migrando para Go, o tempo caiu muito, para menos de 1ms e assim, começou a dar erro de chave duplicada.

A solução? Depende, sempre depende. No nosso contexto, a mais simples foi feita, pois não temos necessidade de otimizar ainda mais a velocidade, até porque mesmo levando 1ms é 20 vezes mais rápido do que já estava rodando e que já atendia com folga a nossa necessidade. Colocamos um simples time.Sleep(time.Milisseconds), para que o processamento dure pelo menos 1ms. A alteração da chave primária não compensaria o esforço.





Latest Images