Devaneando

2048 motivos para não programar

4

2048

Pronto, posso programar em paz. O jogo 2048 é uma lástima para todos os trabalhadores intelectuais que dependem de suas mentes para produzir algo que preste. Ele gerou mais posts no Hacker News do que a moda dos bitcoins (talvez não) e mais projetos no GitHub do que a busca para a cura do câncer (talvez não). (Obviamente que este post vai gerar mais um commit Python no repositório de artigos.)

Não sou fã de jogos, e dos poucos que participei logo parei (exceções honrosas: Portal e Portal 2, esses malditos). Posso dizer o mesmo de 2048, a versão de uma espécie de jogo já conhecido feita pelo italiano Gabriele Cirulli em um fds para ele descobrir se seria capaz de fazê-lo. Ele fez e o jogo e de quebra o índice de produtividade mundial cair.

Houve pelo menos dois projetos de I.A. para resolver o problema que consiste em dobrar números múltiplos de 2 em um quadrado 4 x 4 até que se consiga o quadrado com o valor 2048 (e além). O artigo de Nicola Pezzotti explica o mais efetivo deles, de autoria de Robert Xiao (eu acho). O programa desenvolvido por Xiao otimiza o tabuleiro do jogo guardando-o em um inteiro de 64 bits, deixando 4 bits para cada casa, mais que o suficiente para que seja armazenada a potência de 2 localizada no quadrado (o limite fica sendo de 2 ** 16, ou 65536). Ao rodar a versão executável console ele imprime cada posição do tabuleiro em um formato fácil de ser lido, como este:

Move #69, current score=584
 1356
 0051
 0012
 0000

Como pode-se perceber, cada número diferente de zero contém a potência de dois que ocupa a casa (1 é igual a 2, 5 é igual a 2 ** 5 = 32 e assim por diante). Para alinhar corretamente o tabuleiro os números estão impressos em hexadecimal, ou seja, os valores válidos vão de 0 a f (15).

Isso já seria o suficiente para desvendar os movimentos da I.A., mas nada como um apelo visual. Que tal um vídeo?

Feito com a ajuda de um tabuleiro-template e um pouco do poder Python+PIL:

from PIL import Image
from PIL import ImageFont
from PIL import ImageDraw
from itertools import islice
 
TilePositions = [
        [32, 216], [153, 216], [274, 216], [395, 216],
        [32, 339], [153, 339], [274, 339], [395, 339],
        [32, 461], [153, 461], [274, 461], [395, 461],
        [32, 584], [153, 584], [274, 584], [395, 584]
	]
TileSize = 106
 
def LoadTemplate():
	img = Image.open('2048.png')
	draw= ImageDraw.Draw(img)
	return img, draw
 
 
def DrawBoard(board):
	img, draw = LoadTemplate()
	bigFont = ImageFont.truetype('DejaVuSans-Bold.ttf', 48)
	smallFont = ImageFont.truetype('DejaVuSans-Bold.ttf', 24)
	dbgFont = ImageFont.truetype('DejaVuSans-Bold.ttf', 8)
	for r in range(len(board)):
		for c in range(len(board[r])):
			number = 2 ** board[r][c]
			if number > 1:
				tileX, tileY = TilePositions[r*4 +c][0], TilePositions[r*4 +c][1]
				font = smallFont if number > 64 else bigFont
				text = str(number)
				textW, textH = draw.textsize(text, font=font)
				x, y = tileX + (TileSize - textW) / 2, tileY + (TileSize - textH) /2
				dbgText = str(tileX) + ' + (' + str(TileSize) + ' - ' + str(textW) + ') / 2'
                                draw.text((x, y), text, (0,0,0), font=font)
	return img
 
 
def ReadNextBoard(f):
	lines = [lines for lines in islice(f, 4)]
	if (len(lines)) == 4:
		board = [
			[ int(lines[0][0], 16), int(lines[0][1], 16), int(lines[0][2], 16), int(lines[0][3], 16) ],
			[ int(lines[1][0], 16), int(lines[1][1], 16), int(lines[1][2], 16), int(lines[1][3], 16) ],
			[ int(lines[2][0], 16), int(lines[2][1], 16), int(lines[2][2], 16), int(lines[2][3], 16) ],
			[ int(lines[3][0], 16), int(lines[3][1], 16), int(lines[3][2], 16), int(lines[3][3], 16) ]
			]
		return board
	return None
 
def ProcessGame(filePath):
    f = open(filePath)
    board = ReadNextBoard(f)
    boardNumber = 1
    while board:
            DrawBoard(board).save('2048-' + str(boardNumber) + '.png')
            board = ReadNextBoard(f)
            boardNumber = boardNumber + 1

Note que a estratégia basicamente é ordenar as casas em um lado e, assim que acumular valores o suficiente, consolidar tudo na última casa. Nem sempre isso é possível, pois uma virada de jogo pode deixar a casa com o maior valor no meio de um dos lados. Nesse caso, é interessante ver como a I.A. se sai, já que com apenas uma execução ela foi até 8192 e mais um 4096. Dá-lhe, computador!

Observação importante: para que o conversor Python funcione ele exige um arquivo que tenha *apenas* as posições do tabuleiro dispostas como nas 4 linhas acima. Nada que um grep "^[0-9a-f][0-9a-f][0-9a-f][0-9a-f]$" na saída do jogo não resolva.

Dica: como criar seus próprios vídeos a partir de uma porrada de PNGs.

Ah, sim, se você pretende analisar a estratégia do jogo passo-a-passo, acho que é melhor você dar uma olhada no log do jogo (ou usá-lo para gerar seus PNGs).

Brinde: versão 2048 do Vida de Programador!

Real Programmers Don’t Use Java

0

real-programmer

When I was a newbie (and a wanna-be) I enjoyed reading "Real Programmers Don't Use Pascal", a satiric text that influenced and encouraged me into the path of "C/C++ enlightenment", most even than K&R's book. Since then I thought that being a "Real Programmer" was something close to everything one needs to know to get (hard) things done (quickly). Being a "Quiche Eater" was, in couterpart, comparable to nothing. Real Programmers solve real problems! Quiche Eaters are losers who study the academic concepts of computer science and never do a damn useful and/or working program (maybe you know some guy like this).

Jokes apart, the spirit of the text can also be used by those who already find them very good programmers and believe no longer have to grow professionally. The times my ego inflates I still remember that my code use child APIs and an operating system that is a joke. I also remember that there are some people out there designing a starship that will leave the orbit of the Solar System!

On the other hand, many people that just got out of CS course still find programming a difficult matter. This text reminds us that life was difficult 20, 40, 70 years ago, when engineers and programmers were the same person and when you didn't know that what you were doing could put millions at risk in a project.

Hence, the Real Programmer live in the past. And he always will be worthier than young folks, because he knows how to solve that blue screen problem that nobody else does. As I always say, paraphrasing an illustrious figure in Brazilian television, who is afraid to open Visual Studio and is eternally designing the software instead does not go very far: "who knows to do, do it right way!" .

Here follows a brief summary of the original text adapted to the current times and with my prejucided view of thinking about it. If you wish to use your politically correct piece of mind and criticize me, be my guest!

Languages. Remember: the need to invent more languages/resources to do your job is to remind yourself about your own incompetence to invent such excuse. You are one of those who says "every problem has a specific tool" or something like that. In other words: an inefficient programmer. Don't you see that everything you need is C. If C won't do, then assembly will. If none of them, then is isn't worth doing.

Structured Programming. It is the first and last paradigm to be applied. After all, Object Orientation is another excuse to not program. They are more abstractions that, once you are a dead weight, you are unable to solve a problem using just functions and variables. No, you need classes, inheritance, templates and whatever the hell that will transform your simple and straight code into a magical horn of plenty that will only impress others at the futility and complexity of the solution.

Data structure. Another great concept to fool yourself. Today are many who enslave us to weird SQL layouts and weird frameworks that do all the work. We all know that the only really useful to know the structure is the array. The rest are variants of the same theme: queues and stacks.

Operating system. Mac and Windows are just toys and Linux is a video game that takes more work to set up than playing. The programmer actually uses something like mainframes or other beta operating system, which are too weird and can make a real mess in the hands of those who have not read the WHOLE manual. And knowing all known major kernel bugs and its location by heart at the time of booting is vital.

Tools. If you depend on an IDE that have Code Completion and other fancy stuff or any other editor that depends on your favorite 17,459 plugins installed, then you are not a Real Programmer. A Real Programmer actually use what he have on hand at the time, like notepad, hexdump or even some beeps . The tool is no limit to one that can really code.

Debugging. Are you saying that you need the source code in order to debug? So you do not have a clue of what the program does. Just a few glances at call stack and the registers can make a Real Programmer solve a bug that Quiche Eaters would not get after analyzing those charts with boxes inside UML and use cases for months.

The Real Programmers Work is certainly not doing trivial databases to trivial programs that access SQL with trivial queries. Neither are those horrible websites with PHP/Apache and scripts and more scripts written by kids. No, sir. These are programs that deal with the OS in a more intimate way (HD encryption, file system drivers, critical communication services, etc.), or are programs that do something really useful (compilers, the operating system itself). Or maybe those programs that deal directly with hardware (complex microcontrollers, robots, ships, medical devices, etc.).

The Fun of every Real Programmer is actually chat with friends (about programming), read something (about programming) and watch intelligent movies (about programming or people who have some kind of intellectual challenge to solve "the hard way"). Is there anything more fun than that?

And, finally, in their Natural Habitat, we can find pages and pages of assembly code scattered around the table, a computer locked by a remote kernel debugging serial cable, some notes in hex on a piece of paper, a few dozen browser pages openned about the behavior of functions in BIOS SATA HDDs with 500 GB working on RAID4, coffee (of course), chips, stains on the carpet. When there's nothing to do the environment is pretty tidy and one cannot notice the presence of Real Programmers in sight.

And the Future of Real Programmer? Well, C may even be dying. But so what? It seems C++ supports pointers as well. The rest of the useless abstractions like classes and inheritance may be totally ignored. The basics will always exist. Forget versions with multiple inheritance and enigmatic concepts. Be a (wo)man!

The real, happy, final truth is: regardless of how much more the world becomes "managed" behind frameworks and programmers who prefer to "do projects" behind their office packages and use cases, when problems pop up, some bug murky life threatening useful for a project, a Real Programmer will be there to save the day, because only a programmer really knows how to do his job well done and have a good night of sleep knowing that everything will just be OK.

If it doesn't, there will be always a Real Programmer to save the day.

"As long as there are ill-defined goals, bizarre bugs, and unrealistic schedules, there will be Real Programmers willing to jump in and Solve The Problem, saving the documentation for later. Long live FORTRAN!"

logo

Sobrecarga de função às avessas

4

Navegando pelo Archive.org, que possibilita viajar no tempo e encontrar coisas enterradas que seria melhor deixar por lá, consegui encontrar um post que se perdeu na dobra espaço-temporal entre o old-fashioned Caloni.com.br (com direito à velha joaninha psicodélica, desenho do meu amigo t@z) e o finado CThings. No final, consegui matar a marmota, chegar a 80 milhas por hora e voltar para o presente. Enjoy it!

Alguém já se perguntou se é possível usar sobrecarga de função quando a diferença não está nos parâmetros recebidos, mas no tipo de retorno? Melhor dizendo, imagine que eu tenha o seguinte código:

GUID guid;
wstring guidS;
 
CreateNewGUID(guidS); // chama void CreateNewGUID(wstring&)
CreateNewGUID(guid); // chama void CreateNewGUID(GUID&) (o compilador sabe disso)
// Codigo-fonte disponivel no GitHub https://github.com/Caloni/Caloni.com.br.

É um uso sensato de sobrecarga. Mas vamos supor que eu queira uma sintaxe mais intuitiva, com o retorno sendo atribuído à variável:

GUID guid;
wstring guidS;
 
guidS = CreateNewGUID(); // chama wstring CreateNewGUID()
guid = CreateNewGUID(); // chama GUID CreateNewGUID() (o compilador sabe disso?)
// Codigo-fonte disponivel no GitHub (Caloni/Caloni.com.br) 

Voltando às teorias de C++, veremos que o código acima NÃO funciona. Ou, pelo menos, não deveria. Só pelo fato das duas funções serem definidas o compilador já reclama:

error C2556: 'GUID CreateNewGUID(void)' :
overloaded function differs only by return type from 'std::wstring CreateNewGUID(void)'

Correto. O tipo de retorno não é uma propriedade da função que exclua a ambigüidade. Apenas a assinatura pode fazer isso (que são os tipos dos parâmetros recebidos pela função).

Pois bem. Não podemos fazer isso utilizando funções ordinárias. Então o jeito é criar nosso próprio "tipo de função" que dê conta do recado:

struct CreateNewGUID
{
   // o que vai aqui?
};// Codigo-fonte disponivel no GitHub (Caloni/Caloni.com.br) 

Pronto. Agora podemos "chamar" a nossa função criando uma nova instância e atribuindo o "retorno" a wstring ou à nossa GUID struct:

guidS = CreateNewGUID(); // instancia um CreateNewGUID
guid = CreateNewGUID(); // instancia um CreateNewGUID. A diferen?a est? no "retorno"// Codigo-fonte disponivel no GitHub (Caloni/Caloni.com.br) 

Uma vez que criamos um novo tipo, e considerando que este tipo é, portanto, diferente dos tipos wstring e GUID já existentes, devemos simplesmente converter nosso novo tipo para cada um dos tipos de retorno desejados:

struct CreateNewGUID
{
   operator wstring () { ... } // a convers?o ? a "chamada da fun??o".
 
   operator GUID () { ... } // E como existem duas convers?es... sobrecarga!
};// Codigo-fonte disponivel no GitHub (Caloni/Caloni.com.br) 

E isso conclui a solução meio esquizofrênica de nossa sobrecarga às avessas:

// instancia um CreateNewGUID e chama CreateNewGUID::operator wstring()
guidS = CreateNewGUID();
 
// instancia um CreateNewGUID e chama CreateNewGUID::operator GUID()
guid = CreateNewGUID();// Codigo-fonte disponivel no GitHub (Caloni/Caloni.com.br) 

Eis o fonte completo:

#include <windows.h>
#include <objbase.h>
 
#include <iostream>
#include <string>
 
using namespace std;
 
 
struct CreateNewGUID
{
   operator wstring ()
   {
      GUID guid = operator GUID();
      OLECHAR buf[40] = { };
      ::StringFromGUID2(guid, buf, sizeof(buf));
      return wstring(buf);
   }
 
   operator GUID ()
   {
      GUID guid = { };
      ::CoCreateGuid(&guid);
      return guid;
   }
};
 
 
 
int _tmain(int argc, _TCHAR* argv[])
{
   wstring guidS;
   GUID guid;
 
   // instancia um CreateNewGUID e chama CreateNewGUID::operator wstring()
   guidS = CreateNewGUID();
 
   // instancia um CreateNewGUID e chama CreateNewGUID::operator GUID()
   guid = CreateNewGUID();
 
   wcout << L"Pra nao dizer que esse exemplo nao imprime nada:\n"
         << guidS << L'\n';
 
   return 0;
}// Codigo-fonte disponivel no GitHub (Caloni/Caloni.com.br) 

Voltando à pergunta original: penso que, com criatividade e C++, nada é impossível =)

Fonte: semichaotic.spreadshirt.com

Vida e Software

5

Fonte: semichaotic.spreadshirt.com

Desenvolver software está bem longe de ser uma ciência exata e muito próxima de ser uma ciência humana. Eu, pessoalmente, considero um ramo esotérico, onde vale muito mais ter a atitude de reconhecer que não temos muito controle sobre como as coisas funcionam do que querer ter as rédeas de algo desgovernado.

Não sei bem o motivo. Talvez por existirem muitas camadas o software não consegue ser normalizado como as propriedades físicas dos blocos que montam um prédio ou um transatlântico. Ou simplesmente existem variáveis demais na própria camada da aplicação que impedem a compreensão total do problema (como sabemos se estamos dentro da Matrix? Como o software sabe se está em um ambiente virtualizado?).

Para os piores casos, o software sempre vai ter que confiar em seu ambiente e as regras, aparentemente imutáveis, que o regem. Ele precisar confiar não o exime de controlar seus próprio limites, e é aí que recai a atitude do programador, atitude essa que reflete diretamente nossa visão sobre a vida.

Já vi muitos programadores (eu me incluo) deixando o código pronto para o melhor dos mundos e dando a tarefa por concluída. Otimismo demais? Desleixo? Ou arrogância? Qualquer que seja o motivo, ele está incrustado na própria visão de vida do programador e de como ele se vê no mundo. Eu, particularmente, fico horrorizado com código assim. Não com todos, mas com os que são visivelmente importantes e que necessitam de um carinho especial. São os alicerces para outros códigos, de repente.

Outra atitude igualmente deformada é achar que o mundo vai acabar se não existirem todos os sanity checks (até os mais bizarros) em qualquer meia-dúzia de linhas. É o paranóico, que pode se dar bem no tipo de código importante já citado, mas que nunca vai conseguir entregar um projeto trivial se for baseado em libs escritas pelos outros e cujo código nunca deu uma "lida rápida". Aliás, essa mesma atitude "deu uma lida" demonstra que o pessimista pode ser ainda mais arrogante, pois acredita conseguir capturar toda a complexidade do sistema apenas lendo seu código en passant.

De uma forma ou de outra, como toda atividade humana, escrever código nos define não apenas como bons programadores, mas como bons humanos, com seu conjunto de crenças e valores. O que, de certa forma, é um bom sinal, pois melhorando como seres humanos, melhoramos como programadores. E vice-versa.

Para devanear mais

reorganizando-meus-feeds-de-novo

Reorganizando meus feeds (de novo)

3

Depois da minha opinião dada ao Efetividade na matéria sobre ferramentas para gerenciar as leituras tenho que atualizar que não utilizo mais o esquema das estrelinhas, porque acabei me dando conta que nunca lia o que marcava para ler "depois".

Porém, ainda utilizo o Google Reader por uma série de motivos:

  • Integrado com as ferramentas Google, que eu venero;
  • Tem atalhos no teclado, que eu venero
  • Consigo anotar o que quiser em qualquer página que navegar;
  • Posso organizar os feeds por categorias.

Minha organização de feeds, até semana passada, usava categorias específicas (programação, cinema, economia) e tinha duas categorias no topo que organizava por frequência (diário, semanal), seguindo uma dica de um leitor do Efetividade. Porém, meu maior problema sempre fora os feeds que cospem milhares de entradas por dia, e que sempre ficava para ler no meu fim-de-semana, consumindo às vezes o dia inteiro!

Por isso, para evitar ser abarrotado de notícias, mantenho a seguinte organização de categorias:

  1. Notícias: todos os feeds que cospem milhares de entradas. Organizo por "mágica" e leio apenas os que ficarem no topo. Ao final, clico no famigerado "Mark all as read" e fim de história.
  2. Diário: leituras imediatas, que não requerem mais que cinco minutos, como a tirinha do Dilbert e minhas pesquisas cadastradas no Google.
  3. Semanal: leitura um pouco mais demorada, para quando tiver mais que 10 minutos sobrando.
  4. Amigos: todos os feeds das pessoas que eu conheço e acompanho.
  5. Pessoal: meus próprios feeds, para reler o que eu escrevi e capturar "o outro lado da comunicação" (você, leitor).
  6. Fóruns: mensagens do grupo de programação C++, por exemplo. Está no final da lista porque posso dedicar um pouco do fim-de-semana para ler a evolução dos tópicos, ou até colaborar quando tiver algum conhecimento a acrescentar.

Além disso, os Shared Itens estão configurados como Start page, sendo que tudo que eu anotar durante minha navegação deve ser lida quando eu abro o Reader (incluindo minhas anotações).

Basicamente é isso. Espero não ter que mudar novamente a estrutura. Se tiver, que seja pra melhor.

Idéias?

Base64

1

No meio dos meus artigos pendentes, encontrei esse, de Luiz Rocha, que fala sobre a dificuldade de entender o que seria Base64:

"Salve Caloni,

Já leio o seu site a algum tempo. Realmente acho complicado, alguns eu nem entendo =D.  Mais eh o seguinte, eu estou montando um projeto, mas eu não entendo nada de trabalhar com binários. Então pesquisei na internet, e achei um algoritmo que pode me ajudar, na lógica. É o base64 mas eu não entendi como ele converte e desconverte em binário. Será que vc pode me ajudar, obrigado!!"

Não é a primeira pessoa que pede informações sobre algo específico demais para explicar (para isso existe a Wikipedia e o Google, não?). No meio da minha escrita, percebi que já havia escrito sobre os fundamentos do conhecimento por trás da criação do Base64, conhecimento esse, acredito eu, todo programador que quer sair do lugar com os próprios pés deve ter.

Bônus:

REALMENTE para iniciantes:

Acredito que tudo que um programador precisa saber é o básico. O problema é que esse básico cresce a cada ano, mas, de qualquer forma, continua sendo necessário voltar às raízes de vez em quando, e se existe algo que ele nunca deve esquecer, é isso.

Até porque na programação, 90% não se cria, se copia.

Imaginemos o cenário para a criação do Base64:

Alguns meios de comunicação, notadamente envio de e-mails e a navegação web, por incrível que pareça, trabalham em um protocolo totalmente em modo texto. É até fácil de entender, pois quando essas tecnologias nasceram as limitações de velocidade e estabilidade das conexões permitiam apenas o envio de texto puro de uma ponta a outra.

Isso quer dizer que, na prática, os anexos de um e-mail e as imagens de uma página trafegam, pelo protocolo definido, em modo texto.

Como isso é possível?

A solução não é tão obscura quanto possa parecer. Se um programador médio tivesse esse problema e nenhuma solução existisse ainda, ele faria o que sempre fez para resolver problemas desse tipo: codificar a mensagem na forma permitida. Isso já é feito com o próprio texto, que é apenas uma interpretação de tabelas de caracteres.

Tudo que é necessário fazer é o contrário, mas usando a mesma lógica: montar uma tabela de caracteres válidos e traduzir para um conteúdo binário, sendo que todas as combinações possíveis devem caber nessa tabela.

A forma mais básica binária de comunicação é um byte, constituído por 8 bits, que combinados darão 2^8 entradas em nossa tabela, que precisaria de 256 caracteres diferentes. Como isso ultrapassa o limite dos protocolos que estamos lidando, que em sua maioria utilizam a tabela ascii básica, que possui 128 posições, sendo que algumas posições não possuem caracteres imprimíveis, decidiu-se usar o múltiplo anterior: 64 posições, o que nos dá a chance de codificar 6 bits de cada vez (2^6).

Esse padrão de codificação se chama Base64. Se quiser mais detalhes, basta ler a RFC, que é pequena e muito simples de se ler.

Agora, como codificar essa solução? Só entendendo o básico, é claro.

Mudança

7

Fecha uma porta...

Desde que comecei a programar profissionalmente, lá por volta de 2001, sempre estive envolvido com uma ou duas empresas de Segurança da Informação, na época uma promissora carreira, com direito a hacking, engenharia reversa e outras diversões. Até programar por programar valia!

O tempo passou, completei uma década na área, e agora está realmente na hora de tentar programar coisa nova. Dessa forma, acompanhando minha própria tendência de investidor pessoa física na bolsa de valores, resolvi dar um novo salto em minhas aspirações nesse campo igualmente fascinante e apostar meu tempo de programação também no setor financeiro, onde C/C++ também corre na veia.

Aprendi muito nesse tempo todo com alguns amigos entusiastas (até demais) e programei muito código que gostaria que não tivesse meu nome nos comentários. Mas a vida (e o código) é assim: melhora com os erros.

... e abre outra!

A empresa que estou deixando agora está à caça de uma pessoa para se tornar minha versão 2.0. Dessa vez não é uma busca por talentos inexperientes, de forma que estaremos aceitando apenas pessoas que já se f... com larga experiência em programação Windows.

Segue a descrição da vaga, feita por mim mesmo, sozinho. Interessados: sem timidez, please.

Analista Programador C++

Conhecimentos avançados em Windows: serviços, DLLs, (drivers desejável).
Programação: libc, Win32 API, (STL/Boost e Assembly 8086 desejáveis).
Ferramentas: Visual Studio 2003, Bazaar, VMWare, (WinDbg desejável).
Funções: codificação, análise, reunião técnica, refatoração, (UML desejável).
Perfil: vontade de aprender, pró-atividade, comunicação.

(more...)

Reunião de programadores C++ (há 5 anos)

0

Começo de ano, hora de fazer backup completo. Durante minha cópia anual do gmail acabei encontrando meu post-chamado para nossa primeira reunião C++. Como parte da sessão nostalgia, convido-os, novos e velhos colegas, a continuar a brincadeira de organizar uma reunião informal de pessoas que gostam tanto de programar que criam seus próprios ponteiros.

E-mail escrito em 02/12/2005:

Um dia desses conversando com o Rodrigo Strauss, falando sobre como é interessante trocar informações e experiências sobre C++, ele teve a brilhante e original idéia (ninguém nunca fez isso antes) de propor encontros razoavelmente regulares para fazermos isso. A idéia dele era mais ou menos essa:

  • Peridiocidade dos encontros de X em X meses. Ainda não fechamos isso;
  • X pautas por reunião, votadas pelos participantes. Já temos algumas sugestões como, recursos arcanos do C++ (essa, de acordo com ele, seria minha função), ferramentas, bibliotecas, organização de código etc;
  • Troca de experiências sobre C++ em diversos sistemas operacionais. Por exemplo, nós mostraríamos para o pessoal de UNIX o Visual C++ e aprenderíamos com eles sobre emacs ou KDevelop;
  • Começar de forma muito simples, como uma mesa redonda, e se a coisa avançar, arrumar um lugar para palestras e apresentações;
  • Reuniões em bares ou restaurantes onde possamos conversar, levar acompanhantes e nos sentirmos seguros levando notebooks ou Pockets. Podemos até subir uma rede wifi e aumentar a diversão :-)
  • Como eu e o Strauss somos de São Paulo (na verdade, eu sou de São Bernardo), os primeiros encontros seriam na capital;
  • Isso é uma boa desculpa para se encontrar e tomar um chopp || guaraná || cachaça.

Gostaríamos que as pessoas da comunidade C++ dessem sugestões sobre essa idéia. Estamos pensando em agendar o primeiro encontro para dia 17/12/2005 (sábado) durante a tarde, em um Outback (comida australiana, Shopping Center Norte ou Eldorado, tem infra para crianças e a comida é muito boa). Como pauta do primeiro encontro eu sugiro uma apresentação dos participantes (o que será desnecessário se só eu e o Strauss aparecermos) e uma discussão sobre o presente e o futuro do mercado de trabalho C++.

Coloquem as sugestões nos comentários e quando a gente fechar alguma coisa eu escrevo um novo post com o que definimos. Até lá.

PS: Qualquer semelhança deste post com o conteúdo de um conhecido blog brasileiro sobre programação não é mera coincidência.

(more...)

Erro de automação?

Suporte técnico

2

Máquina com parte do registro corrompida, notadamente alguma sub-chave de HKEY_CLASSES_ROOT. Resultado: ao rodar um script que abre uma segunda janela e tenta usar seu método focus é exibida a seguinte mensagem:

Erro de automação?
"<Mensagem do cliente> - A classe não dá suporte para automação"
Abaixo um exemplo simples para ter uma ideia em JS:

var win = window.open('minha_url_do_coracao.htm');
win.focus(); // aqui dá o erro

A primeira coisa que se faz nesse caso é pesquisar no Google por pessoas que já tiveram esse problema. A maioria dizia ser necessária registrar novamente as DLLs do navegador/shell, coisa que fizemos à exaustão e não resolveu o problema. Também imaginamos haver relação com a versão da SDocVw.dll que estava alocada na lista de assemblies .NET cacheados, o chamado GAC. Ou seja, já estávamos viajando geral.

(more...)

twitter_bird.jpg

Twitter, eu?

0

twitter_bird.jpgFico meio receoso de comentar aqui que, sim, eu tenho twitter, e, sim, sou praticante de mais uma das artes da vadiagem. Até porque se 5% dos meus tweets tiver alguma relação com o conteúdo desse blogue, é  muito. O resto são comentários sobre economia&finanças, notícias aleatórias sobre alguma descoberta científica (ou não), dicas rápidas sobre cinema e sabe-lá-deus-o-que-mais.

E isso não vai mudar. É meu twitter pessoal. Aliás, meu próprio blogue também é pessoal, e é provável que no futuro ele que mude, e não o contrário.

Isso não quer dizer que vou deixar de ser programador. Acho que depois de dez anos programando sem parar essa opção não existe mais, pois as habilidades adquiridas já foram registradas no meu código genético. Só que, no meu caso, ser programador não evita que eu tenha uma porção de outros interesses e que me dedique a eles tanto quanto programação.

Dito isso, segue mais um ponteiro perdido pela rede.

(more...)

Go to Top