nunojob:~ dscape/08$ echo The Black Sheep

Archive for the ‘Technology’ Category

dreamhost insanity day

The deal was – well – insanely good.

Unlimited storage and traffic, 1 domain name (plus all the extras) for two years. If you inserted 202 as promo code you would get a final price of 11USD.

I was lucky enough to get an update from Pedro while dreamhost was working and got a great deal. Even got a new domain name I was looking for: dscape.org! Yay! I had to use Google Checkout to buy as the website was not very stable and I didn’t want to risk it with a credit card transfer.

As one would expect *not* dreamhost.com was down for most of the day after the news started spreading on twitter. Dreamhost guys called that sluggish!? A hosting company website down by self DoS attack? As Alanis Morrissette would say “isn’t that ironic?”

The only thing visible thing that dreamhost did to change this was change the price to 22USD. Whoever decided that is clearly not the brightest crayon in the box. A hosting company is about having a stable service. You never charge different prices for the same service in the same day. If you want to do an insane promo, be prepared. Is it that hard to come up with a way to get the same (or more) customers without having your website on his knees and old customers leaving your service??

Final Considerations: How many cancelled their subscriptions paying 10USD a month for this deal? How much of a money loss will that represent for dreamhost? Is this a clear sign of a urgent need for income? Is it just insanity? How much money did Google made on this (1USD per transfer)? How many new domains were registered today?

IBM DB2 Express-C em versão mac

DB2 for Mac

DB2 for Mac

É oficial. A versão GRÁTIS do DB2 está disponivel para download para mac.

Acabaram-se as desculpas do não quero outra maquina virtual para correr isso, nem sequer experimento.

Eu sei que sou suspeito para falar já que faço parte da equipa DB2. A análise que vou aqui fazer é muito influenciada pelo meu dia a dia no trabalho mas o que escrevo aqui é a minha opinião pessoal .

A IBM não trabalha no DB2 para pessoas como nós que têm uns sites jeitosos com alguns milhares de hits diários (com sorte). Eles fazem isto para aguentar soluções de escala gigante, algumas com standards pesados em  XML de agências governamentais, financeiras, health-care, etc, que transaccionam quantidades enormes de informação diáriamente. Essas empresas não só tem que minar os dados como fazer queries sobre eles de uma forma bastante intensiva. Estou a falar das maiores empresas americanas, e não o digo decor. Ouvi-o da boca de DBAs da Merrill Lynch, Barclays, ONU, Morgan Stanley, etc.. Que tem eles em comum? Todos eles usam DB2 e estão interessados em usar as funcionalidades XML do produto.

Já agora ninguém confia que seja possivel ter performance em XML certo? Bem a IBM tem pessoas inteligentes (como eu, lol) a trabalhar em tornar isso possivel. Deixo este link para vos aguçar o apetite. Claro que a performance não será a mesma que SQL mas comparado com os parsers xml que andam a usar… eheh. Exprimentem. :P

Como já descrevi o cliente normal do DB2 é facil constactar que não é feito para vender a José, ao Joaquim. Nem sequer a pequena empresa da Josefina. A versão Express-C é gratís para todos por isso mesmo. As limitações são um máximo de 16Gb de ram e 4 processadores na maquina.

Se isto parece razoavel:

DB2 for Mac Download

DB2 for Mac Download

Depois contem como correu e se precisarem de umas dicas podem sempre entrar em contacto.

Footnote: Para os interessados se estão a desenvolver algo com um standard xml estranho  a probabilidade desse standard ser suportado pela ibm é grande e pode ser consultado aqui.

RSA Encrypt & Decrypt in ruby

Well I finished the encrypt with RSA on ruby some hours ago and felt like sharing :)

Case you feel like doing something back for me just download the latest release of my beta twitter client and send me some comments to my email. It’s pretty hard to test something when my environment is completely contaminated !

require 'openssl'
require 'Base64'

class Rudolph
  class Crypt
    def initialize data_path
      @data_path = data_path
      @private   = get_key 'id_rsa'
      @public    = get_key 'id_rsa.pub'
    end

    def encrypt_string message
      Base64::encode64(@public.public_encrypt(message)).rstrip
    end

    def decrypt_string message
      @private.private_decrypt Base64::decode64(message)
    end

    def self.generate_keys data_path
      rsa_path = File.join(data_path, 'rsa')
      privkey  = File.join(rsa_path, 'id_rsa')
      pubkey   = File.join(rsa_path, 'id_rsa.pub')
      unless File.exists?(privkey) || File.exists?(pubkey)
        keypair  = OpenSSL::PKey::RSA.generate(1024)
        Dir.mkdir(rsa_path) unless File.exist?(rsa_path)
        File.open(privkey, 'w') { |f| f.write keypair.to_pem } unless File.exists? privkey
        File.open(pubkey, 'w') { |f| f.write keypair.public_key.to_pem } unless File.exists? pubkey
      end
    end

    private
    def get_key filename
      OpenSSL::PKey::RSA.new File.read(File.join(@data_path, 'rsa', filename))
    end
  end
end

Rudolph – Yet another Twitter client

I felt like trying the Shoes framework. Here are the results so far. When I get some free time I’ll try to post some guidelines to do something like this.

Webpage: http://the-shoebox.org/apps/105

Github: http://github.com/dscape/rudolph

Apache CouchDB

It’s official. yey! Great news :) 

Damien’s post.

NYU visit to hawthorn

I had to pleasure to be one of the hosts for NYU group visit in Hawthorn. The students were very lucky and got to see really good talks. Robert Morris presented explained why services are so important for IBM and how research applies to business. It was really an excellent spontaneous talk and it was to bad he didn’t stick around so I could talk to him about it. Then they got to see talk on Stream Processing and how to manage real time processing and analysis for quantities of data that are possible considered impossible to handle by most common people. I also managed to see Grady Booch for the first time, in second life. He also gave an great talk about the beauty of software (www.booch.com/architecture/blog/artifacts/Turing%20Lecture.ppt) and showed the potential of second life for this kind of event. By then both Robert and Grady had my curiosity set on the future in what concerns intellectual property but I guess that’s not a good subject for showing IBM to graduate students :) eheh. It finished in beauty  with Laxmi talking about the famous Genographic Project (https://www3.nationalgeographic.com/genographic). For those who still don’t know the genographic project is a joint venture between IBM and National Geographic where they try to find out more about the history of migrations using DNA. Cool!! The social aspect was also really important and I think students were happy with the feedback we gave them about IBM. By the way the lack of blog posts is mostly because Twitter is taking over all my blog post that can fit in under one hundred and something chars.

SVN Hub

Source LeviFig

Clojure – Ulisses this one is for you

Clojure is a dynamic programming language that targets the Java Virtual Machine. It is designed to be a general-purpose language, combining the approachability and interactive development of a scripting language with an efficient and robust infrastructure for multithreaded programming. Clojure is a compiled language – it compiles directly to JVM bytecode, yet remains completely dynamic. Every feature supported by Clojure is supported at runtime. Clojure provides easy access to the Java frameworks, with optional type hints and type inference, to ensure that calls to Java can avoid reflection.

Clojure is a dialect of Lisp, and shares with Lisp the code-as-data philosophy and a powerful macro system. Clojure is predominantly a functional programming language, and features a rich set of immutable, persistent data structures. When mutable state is needed, Clojure offers a software transactional memory system and reactive Agent system that ensure clean, correct, multithreaded designs.

Now that sounds nice right? Give it a try.

Sobre o Windows 7

Como é obvio vou falar mal. Alias diariamente uso windows e é provavelmente a coisa mais infeliz do meu dia a dia.

Anyway acabei de ver um vídeo a mostrar os corners (no windows 7 são top down left e right em vez de actual corners como nos macs) e multi-touch. O senhor que estava a apresentar é descarado o suficiente para dizer que isto é algo que o iPhone tem mas os macs não.

AMIGO: Os corners já existem nem sei a quantos milhões de anos. Quanto ao multitouch já vão alguns meses.. Pelo menos. Mentir para que? Vão sempre copiar a mac. Vão sempre usar o raio do DOS que toda a gente sabe que é foleiro. Se querem inovar. Inovem. Se vão copiar admitam. SIMPLES NÃO?! Já agora, para além de admitir paguem… Eu nem gosto muito de IP mas se a apple fez e vocês copiaram então paguem. Ponto!

Conselho de amigo. Querem fazer algo de jeito deitem lá fora isso que chamam Windows e começem do zero. Com esse código nunca na vida vão lá.

Posts Relacionados Sugeridos de Uma Forma Descarada na Secção dos Comentários :P

Git, SVN, CVS

Just a few days ago I was talking to a friend of mine completely astonished that he was using CVS at work. Not only he was using it, he was being taught how to use it. I told him about SVN existence and the fact that even though SVN (Subversion) was some kind of evolution on CVS it still sucked big time. I then showed him some of my projects on git and some popular website that make it easier to track your git repo. I went on trying to explain how much easier, more reliable and light git was and how it was a really wonderful piece of software for any developer. Open source does make the world a better place. What I had no clue about was that git was originally written by Linus Torvald. Really I had no idea until today when I found this talk on this old friend from prt.sc.

No reason to disapear

Well ever since I started working time for my blog has been less. I really dislike that as this little corner gives me a lot of joy not only in the moment of writing but also for the great joy that is sharing information and enabling others to learn new and exciting technologies. That’s one of the things I want to talk about today. The power of sharing.

Last two weeks I was contacted by people (mostly experienced people) that were using either my k-anonimity algorithm or my open source online testing system. The fact that people are using my silly scripts is rewarding enough but the networking opportunities and being a person enabler is really what thrills me the most. It’s pleasant to see people overcome their difficulties, help them learn a new technology and then seeing the final result. I hope to continue receiving your kind emails about my work. I will always have 5 minutes to help.

I think that if you are a blogger but you don’t share what your doing your missing out. Your code will vanish into some CD or will just remain in some folder, buried forever. Let your code live. Let it enable others. Let it grow. In the meantime it will help you get wherever you want. Actually I got another exciting news just for sharing. But unfortunately I cant disclose them just yet. It involves being invited to help writing a free Ruby on Rails book. Sorry, had to say it :) How cool is that?

Actually, the most boring thing about working at large corporation is the fact that you cannot share what you do. It no longer belongs to you and even if it’s ok to share it you have to follow a complex process to get authorization to do so. So no one does! Everybody is waiting to sue so you simply can’t do things that you assume would be ok. Referring a copyright brand without referring that the brand belongs to x can cost the company a significant amount (and your job :P) and they simply can’t risk it. But oh well. The least you can say is that the good things cancel that out.

I have beenworking on DB2 and I’m widely surprised by the quality of the pureXML support and overall behavior of the solution. The lack of advertising and tools that IBM distributes with DB2 doesn’t give you the same amount of trust that other better advertised and with better tools databases do. But when you get down to business you will realize that DB2 and Oracle are on a league of their own. Just talking to the clients will make you realise that they buy because other databases can’t handle the amount of information. And if you do XML, for the next 6 months at least I’m sure that DB2 will be miles ahead. How much longer will it take for companies to realize that storing xml in clobs ain’t probably the best solution? Anwser: Not much…

Oh, final note! I finally picked the theme for my masters thesis. It will be about data mining in xml databases so if you feel like you have a nice tittle suggestion for it just leave it in the comment box. It will be greatly appreciated.

Guia para usar windows

Não está a funcionar? Reboot, esperar 25 minutos, usar enquanto está a carregar uns programas. Começar a trabalhar com 75% da ram ocupada e o processador com vários processos a concorrer por tempo. Bem bom..

Depois do reboot continua a não funcionar? Format. Agora já funciona! :) 75% da memoria ocupada, o java irá provavelmente crashar o computador nas próximas duas horas. Bluescreen assegurado uma vez por semana.

É isto que o pessoal chama enterprise ready. Yeah right. Montam coisas em cima de coisas sem se preocuparem com a qualidade.

Use linux! três razões (podiam ser 30 mil mas fico por aqui)

  • Mais barato
  • Mais fiavel
  • Mais rapido
  • Menos crashes
  • Nenhuns reboots
  • Nenhums formats
  • Já alguem usou MSDOS? Não desejo isto a ninguém. É tortura.
  • Tem problema? Vê o codigo e submete a fix.
  • Por ultimo, e para completar esta lista de três. É MELHOR!

Obrigado é tudo.

Lego Mac Pro

Não gosto muito de usar o meu blog para fazer simples foward de um artigo de outro estáminé. Para isso uso o botão share no google reader. (caso me queiram adicionar a lista de amigos, o meu email está aqui)

Mas desta vez não consigo resistir. É que este post no blog da MAKE deixou-me com um sorriso parvo na cara de achar a ideia de fazer um caixa com lego tão fixe. E claro, tinha que ser um mac! Faz-me lembrar dos projectos insanos do Anders como montar um PC numa banheira e por-lo a correr mergulhado em óleo. Até partilhava o link mas não me lembro bem o nome que ele deu ao vídeo no youtube. (Anders where’s the video of the PC you assembled on a bathtub? Because of you this is now the worse post in the history of internet.)

Para que este artigo não seja completamente inútil partilho também que vi que existem empresas que contratam especialistas com legos, especialmente pessoal que trabalha com os technics. É um skill porreiro para fazer protótipos. Na Bang & Olufsen usam lego para a simular a mecânica do prototipo e flash/director para a demonstração interactiva do dispositivo.

Fica a imagem e o link para o artigo original.

Lego Mac Pro 2

Lego Mac Pro 2

myAmbrosio

Para aqueles que andam sempre atentos as novas startups aqui está mais um projecto inovador acabadinho de sair da Universidade do Minho. Apesar de o projecto ainda estar muito verde os autores já contam com algumas parcerias importantes, assim como o sempre necessário apoio financeiro.

A ideia por trás do Ambrosio é um agregador de produtos/lojas de comercio tradicional, servindo este como veiculo de promoção das lojas/produtos e fornecendo aos utilizadores finais produtos que, por exemplo, não conseguem comprar num Hipermercado perto de si. Outro tipo de mercado que se pode abrir é certamento o do turismo rural através de, por exemplo, uma sugestão de onde dormir, onde comer ou indicação de onde estão a decorrer as festas tradicionais da terra.

Caso estejam interessados no conceito podem ver o video explicativo acabadinho de sair e contactar os autores com sugestões.

IBM Data Studio Developer 1.2 Official Release

Foi lançado hoje a nova versão do IBM Data Studio Developer.

Desde que entrei no DB2 Students Group na condição de embaixador tive o privilégio de aprender e mexer com algumas soluções da IBM. Entre o rol de coisas que me agradaram (não vamos falar de coisas tristes, como o IBM_DB adapter para Ruby que na altura estava bastante desactualizado) foram a possibilidade de usar alojar xml nativamente na base de dados. O pureXML com suporte para XQuery foi algo que usei durante o semestre passado em projectos como o Open Source Online Testing System. O facto da LeFevre ter implementado o Mondrian no DB2 também é um ponto a favor para qualquer maluquinho da segurança dos dados. E todos tiveram a oportunidade de ver que implementei o Mondrian no ultimo semestre no âmbito da unidade curricular de criptografia e segurança de sistemas informáticos.

O Data Studio Developer é uma ferramenta para developers que usam DB2. Entre as novidades da nova versão está o suporte para PureQuery e o facto de usar o mesmo tipo de tecnologia de persistencia que a usada no Project Zero. Continuam interessados? Então podem sacar aqui.

Mondrian Multidimensional K-Anonymity in Ruby

Article: Mondrian Multidimensional K-Anonymity

Lame Ruby Implementation:

# ==================================================================================
# anonymization: group.rb
# ==================================================================================
ENVIRONMENT = ‘release’ #’release’

require ‘set’
require ‘rubygems’
require ‘ruby-debug’ if ENVIRONMENT == ‘debug’

# ==================================================================================
# class group
#
# usage:
# require ‘group’
#
# g = Group.new ,
# g.anonymize
#
# example:
#
# lefevre.db
#
# 0 2 < -- quasi_ids # # |age| sex | zipc | disease | #---+---+-------+------+--------------+-- # 0 | 25 Male 53711 Flu | # 1 | 25 Female 53712 Hepatitis | # 2 | 26 Male 53711 Bronchitis | # 3 | 27 Male 53710 Broken_Arm | # 4 | 27 Female 53712 AIDS | # 5 | 28 Male 53711 Hang_Nail | #---+---+-------+------+--------------+-- # # irb # >> require ‘group’
# >> g = Group.new [0,2], ‘lefevre.db’
# >> g.anonymize 2, ‘degen’
# ==================================================================================
class Group
# create a setter method for @tuples, @filename
# so that g.tuples = x works
attr_writer :tuples, :filename

@@debug = { ‘best_attribute’ => ENVIRONMENT == ‘debug’,
‘intersection’ => ENVIRONMENT == ‘debug’,
‘split’ => ENVIRONMENT == ‘debug’,
‘ordering’ => ENVIRONMENT == ‘debug’,
‘vars’ => ENVIRONMENT == ‘debug’,
‘args’ => ENVIRONMENT == ‘debug’
}
# ================================================================================
# to create a new group with Group.new
# ================================================================================
# needs to remove the full_ids from the read.
def initialize(quasi_ids, filename, depth=0, available_ids=nil)
# if no valid attributes are given quasi are used
available_ids = quasi_ids if available_ids.nil?

# initialize the instance vars
@tuples = []
@quasi_ids = quasi_ids
@available_ids = available_ids
@depth = depth

# serves as wilcard so that no file is read on recursion
filename == ‘*wc’ ? @filename = nil : @filename = filename

if @@debug[‘args’] and @depth == 0
debug_puts “args : file => #{@filename}”
debug_puts “args : k => #{@k}”
debug_puts “args : quasi_ids => #{@quasi_ids.to_s}”
end

# run the read and backup procedures
read
end

# ================================================================================
# anonymization
# ================================================================================
def anonymize(k, heuristic=’degen’, partial_order=[])

if @@debug[‘vars’]
#debug_puts “dvars : @tuples #{@tuples}”
debug_puts “dvars : @available_ids #{@available_ids},”
debug_puts “dvars : @depth #{@depth}”
end

# stop case
if isnt_splittable? k
debug_puts “dsplit: no split available for k-level #{k} with size” +
” #{@tuples.size}” if @@debug[‘split’]

# sort and generalize remaining attributes
@available_ids.each do |attribute|
sort attribute
generalize attribute
end

# exit
return
end

# where and in what attribute should we split
# these functions have a heavy effect on the usefulness of the information
# for the k-anonymity table
split_attribute = find_split_attribute @available_ids, heuristic, partial_order
split_pos = find_split_position split_attribute

# create the groups for the
# recursion
group1 = Group.new @quasi_ids, ‘*wc’, @depth + 1, @available_ids.clone
group2 = Group.new @quasi_ids, ‘*wc’, @depth + 1, @available_ids.clone

# split at the given position
split split_pos, group1, group2

if split_groups_satisfy_k_anonymity?(k,group1,group2)

debug_puts “dsplit: no more split available with attribute” +
” #{split_attribute} (g1: #{group1.size}, g2: #{group2.size})” if @@debug[‘split’]

# generalize by split_attribute and then remove it from the available
# attributes array
generalize split_attribute
@available_ids.delete split_attribute

# anonymize remaining available attributes
anonymize k, heuristic, partial_order

else # splitting successful
debug_puts “dsplit: splitting on attribute #{split_attribute} at” +
” position #{split_pos} of #{@tuples.size}” if @@debug[‘split’]

# assign the two groups to this instance
@group1 = group1
@group2 = group2

group1.anonymize k, heuristic, partial_order
group2.anonymize k, heuristic, partial_order

#@tuples = []
end
end

# ================================================================================
# io and backup related
# ================================================================================
# read @tuples from @filename
def read
unless @filename.nil?
f = File.open @filename
f.each_line do |line|
@tuples < < line.rstrip.split("\t\t") end f.close end end # reset the class to reuse def reset @available_ids = @originally_available_ids @tuples = [] read end # ================================================================================ # overrides # ================================================================================ # number of tuples def size @tuples.size end # ================================================================================ # aux # ================================================================================ # to_s def to_s str = "" unless @tuples.empty? @tuples.each do |line| @tuples[0].size.times { |i| str << line[i].to_s + "\t\t"} str << "\n" end end str end # shows a yaml representation of internal object def to_y require 'yaml' y self end private def debug_puts(message) ident='' @depth.times {|i| ident+=" "} puts ident + message end # ================================================================================ # aux for anonymization # ================================================================================ # finds the attribute with the largest range. According to LeFevre this is a good # heuristic to find the attribute on def find_split_attribute(attributes_list, heuristic, partial_order) debug_puts "dorder: choosing from" + " #{attributes_list.to_s}" if @@debug['ordering'] best_attrib = -1 best_attrib_count = 0.0 attributes_list = find_minimal_elements partial_order, attributes_list debug_puts "dorder: minimal list is" + " #{attributes_list.to_s}" if @@debug['ordering'] attributes_list.each do |attribute| values = @tuples.map{|t| t[attribute]}.to_set # degen heuristic: split on the attribute that had more degeneracy if heuristic == 'degen' if values.size < best_attrib_count or best_attrib == -1 best_attrib = attribute best_attrib_count = @tuples.size.to_f / values.size.to_f end elsif heuristic == 'single' if values.size < best_attrib_count or best_attrib == -1 best_attrib = attribute best_attrib_count = values.size end else #default if values.size > best_attrib_count
best_attrib = attribute
best_attrib_count = values.size
end
end
end

debug_puts “dbest : best atribute is #{best_attrib} with” +
” count #{best_attrib_count}” if @@debug[‘best_attribute’]

return best_attrib
end

# returns the position of the leftmost or rightmost median element.
# used to split in lhs and rhs
def find_split_position(attribute_id)
sort attribute_id

median_pos = @tuples.size / 2
median = @tuples[median_pos][attribute_id]

split_pos_high = median_pos
split_pos_low = median_pos

# split point correspond to highest index that has median value
split_pos_high += 1 while (@tuples.size >= split_pos_high + 2) and
(@tuples[split_pos_high + 1][attribute_id] == median)

high_smaller_group_size =
[split_pos_high + 1, @tuples.size – split_pos_high – 1].min

# split point correspond to lowest index that has median value
split_pos_low -= 1 while (split_pos_low > 1) and
(@tuples[split_pos_low – 1][attribute_id] == median)

low_smaller_group_size =
[split_pos_low, @tuples.size – split_pos_low].min

# choose the one with the largest group
if high_smaller_group_size > low_smaller_group_size
split_pos = split_pos_high
else
split_pos = split_pos_low – 1
end

return split_pos
end

# finds minimal elements from the list of the given attribute list according to
# partial order specified in partial_order. partial_order contains all complete chains.
def find_minimal_elements(partial_order, possible_elements)

if partial_order.empty?
debug_puts “dorder: no ordering specified” if @@debug[‘ordering’]

return possible_elements
end

# choose all possible_elements that arent in partial_order
# those are minimal
minimal_list = possible_elements.select { |element| !partial_order.flatten.member?(element) }

# haskell goodies ^^
# restrict partial_order to values in possible_elements
restricted_partial_order = partial_order.map { |l| l.select { |element| possible_elements.member?(element) } }

if @@debug[‘ordering’]
debug_puts “dorder: possible_elements list is” +
” #{possible_elements.to_s}”
debug_puts “dorder: partial_order list is” +
” #{partial_order.to_s}”
debug_puts “dorder: restricted_partial_order is” +
” #{restricted_partial_order.to_s}”
end

non_zero_chains = restricted_partial_order.select { |chain| not chain.empty? }

non_zero_chains.each do |c|
candidate = c[0]

minimal = !restricted_partial_order.any? do |chain|
chain.member?(candidate) and chain[0] != candidate
end

if minimal and not minimal_list.member?(candidate)
minimal_list << candidate end end return minimal_list end # replaces attribute value with generalization that cover all tuples. # Expects tuples to be sorted by attribute. def generalize(attribute) min_val = @tuples[0][attribute] max_val = @tuples[-1][attribute] unless min_val == max_val @tuples.each do |t| t[attribute] = [min_val, max_val] end end end def split(split_pos, group1, group2) group1.tuples = @tuples[0..split_pos] group2.tuples = @tuples[split_pos+1..@tuples.size] end def sort(attribute) @tuples = @tuples.sort_by { |t| t[attribute] } end # ================================================================================ # verbose conditions # ================================================================================ def isnt_splittable?(k) k < 2 or group_cant_be_split_for_level?(k) or no_split_attributes_are_available? end def group_cant_be_split_for_level?(k) @tuples.size < 2*k end def no_split_attributes_are_available? @available_ids.empty? end def split_groups_satisfy_k_anonymity?(k,group1,group2) group1.size < k or group2.size < k end end # hack on array to display lists correctly class Array def to_s "[" + self.join(',') + "]" end end [/sourcecode]

Travelling will change you

I just felt like sharing two things. A thought, and a video.

First the thought. The gift of our generation as is globalization. Don’t waste it. Use it at your own advantage. So go visit the world. Meet great people (1, 2). Try new things. Learn things from different cultures. Be silly. Enjoy yourself.

Each day I feel more eager about taking a next step. And each day I try to anticipate the next one so I’ll be ready when the time comes. What should I learn? What do I feel like doing next? Where can I do the most impact to help myself and others, while enjoying myself? (No Anders, not in that way… Go sit in the corner)

It’s up to you to make things happen and whoever keeps saying you can’t. Well, tell them to fuck off. You can, just try hard enough. It always worked for me and I’m just some average guy from some university lost in the north of corruption paradise.

As responses to my question this is what I figured out. I want to be somewhere where I can do what I’m excited about 100% of the time (so googles out, they only do 20% time. And they seem to be on low wages) I choose the place were I’ll be doing my internship based on the assumption and really think I made the right choice :) But I’ll report on that as soon as I start on October 6th.

Now, the video. This is Randy Pausch. Randy was a excellent teacher that achieved everything he wanted from life (ie). He gave a course (and later a masters) that was similar to what Peter tried to do in CD-DIP Summer School. Very inspiring life story. Kudos to him.

CDDIP 08 – Innovation Camp – First Week in Denmark

CDDIP

Pictures here. I´ll add some presentations and prototypes soon.

Diablo 3 – Cinematic Trailer

Promete.. Podem visitar o site que acabou de abrir a coisa de uma hora.

Mobicomp comprada pela Microsoft

Já lá trabalhei, sai com uma óptima opinião sobre a empresa e uma maior ambição de fazer mais de mim mesmo.

Agora foram comprados pela Microsoft. (2) Já a algum tempo tinha conhecimento da visita que a Microsoft tinha feito as instalações e já suspeitava do negocio.

Parabéns a todos, Carlos, Ricardo, Ernesto, Rui e Marco ;) Parece que já podem comprar um iPhone novo (gostaram da piada?) :P

Nova startup promete arrasar com o maisgasolina

Novo e intrigante email que recebi hoje:

Chegou a concorrência ao maisgasolina e, ao que parece, tem pernas para andar. Um dos autores é Tiago Ribeiro, que foi recentemente premiado pela microsoft (buuh) com o premio great minds, great efforts, e é também o mentor do project e-sharing. Para já deixo-vos o email que recebi.

Olá!

A thirdlabs, em parceria com a InnovationPoint S.A., gostaria de convidar a comunidade académica a participar no seu novo comparador de combustíveis gasmappers.com, que acaba de lançar no mercado nacional. Trata-se de um portal comunitário, de adesão livre e com uma interface intuitiva que permite saber quais os postos mais económicos para abastecerem o vosso carro, de acordo com vários critérios e condições de geolocalização.

Este convite (…), sendo a equipa composta por um aluno do 3º ano do Mestrado Integrado em Engenharia Biomédica da Univ. do Minho (Rui Marinho), por um ex-aluno de Engenharia Informática do Instituto Politécnico do Porto (Sérgio Castro) e ainda por um aluno do Mestrado em Engenharia Informática da Univ. do Minho (Tiago Ribeiro).

Esperamos que desfrutem do site e que contribuam sempre que possível. Estamos abertos a sugestões e comentários, quer via Google groups, quer por email para info@gasmappers.com.

Cuidado com os tigres

Mais uma excelente talk do Steve Yegge.

Scala, now, is the tiger that’s going to kill Java. Because their [type-talisman] argument now has become a paradox, similar to the Paul Graham Blub Paradox thing, right? Because they’re like, “Well, we need static typing in order to engineer good systems. It’s simply not possible otherwise.”

The Scala people come in and they go: “Your type system suuuuuucks. It’s not sound. It’s not safe. It’s not complete. You’re casting your way around it. It doesn’t actually prevent this large class of bugs. How many times have you written catch (NullPointerException x) ... in Java? Our type system doesn’t allow [things like] that.”

Our type system does what you said your type system was doing.

So, therefore, you should be using it! ∴

And the Java people look at it and go: “Wehellll… (cough cough)… I mean, yeah, I mean… (*ahem*)(running finger under collar, as if sweating profusely) They say, “Welllll… you know… it’s awfully… cummmmmbersome… I…”

“We can actually get around the problems in practice that you guys say your type system is solving through Good Engineering Practices.”

(laughter begins to grow)

HA!!! (I point accusingly at the audience, and there’s more laughter)

Yeah.

So Scala is creating a real problem for [Java’s] static typing camp now. Because their last little bastion of why they’re using it, the whole tigers argument, they’re like, “Ah, well… we… we keep shotguns in our house.” [This is what they’ve been reduced to.]

OK? Yeeeeahhhh…

So back to dynamic languages!

Ruby Ruby Ruby Ruby

Parece que fui ao rock in rio ver kaiser chiefs (e fui).

Estava para aqui a brincar ao ruby e assim do nada encontro-me a chamar métodos dinamicamente (ruby as a meta-language) que devolviam strings. Tudo bem até chegar a um que devolvia integer e eis que aparece aquele erro:

NoMethodError in SearchController#search

undefined method `include?’ for 7:Fixnum

Que fazer? Mudar aquela linha de código por um if e contemplar as duas possibilidades? Ou simplesmente alterar o Fixnum e ensinar-lhe o que eu esperava que o include? fizesse? Eu fui pela segunda opção:


class Fixnum
  def include?(object)
    to_i == object.to_i
  end
end

Em linguagens assim dá gosto trabalhar!

Wouldn’t ANTLR be better if written in a dynamic language?

I think making a tool like ANTLR is a non-dynamic language is a shot in the foot!

It just makes sense to use dynamic languages to create meta-language tools. Would facilitate the work of the developer and of the ones writing grammars taking away all that java trash that helps in nothing to make out stuff work. ANTLR is great, but all the negative aspects (from end-user point of view) arise from the fact of having all that unnecessary information and needing to declare types and other stuff that ARE NOT NATURAL for a grammar to have. And the way it’s implemented in Java is just a way of copying the way (bad) dynamic languages work.

grammar Expr; 

options {
  output = AST;
  ASTLabelType = CommonTree;
} 

prog
     : ( stat
         { System.out.println( $stat.tree.toStringTree() ); }
       )+
     ;

stat
     : expr NEWLINE -> expr
     | ID '=' expr NEWLINE -> ^('=' ID expr)
     | NEWLINE ->
     ; 

expr
     : multExpr ( ( '+'^ | '-'^ ) multExpr )*
     ;

multExpr
     : atom ( '*'^ atom )*
     ;

atom
     : INT
     | ID
     | '('! expr ')'!
; 

ID
     : ( 'a'..'z' | 'A'..'Z' )+
     ;

INT
     : '0'..'9'+
     ; 

NEWLINE
     : '\r'? '\n'
     ; 

WS
     : ( ' ' | '\t' | '\n' | '\r' )+
       { $channel=HIDDEN; }
     ;
grammar Expr; 

options {
  output = AST;
} 

prog
     : ( stat
         { puts $stat.to_tree }
       )+
     ;

stat
     : expr NEWLINE
     | ID '=' expr NEWLINE -> ^ // mark the root somehow
     | NEWLINE
     ; 

expr
     : multExpr ( ( '+'^ | '-'^ ) multExpr )*
     ;

multExpr
     : atom ( '*'^ atom )*
     ;

atom
     : INT
     | ID
     | '('! expr ')'!
; 

ID
     : ( 'a'..'z' | 'A'..'Z' )+
     ;

INT
     : '0'..'9'+
     ; 

NEWLINE
     : '\r'? '\n'
     ; 

WS
     : ( ' ' | '\t' | '\n' | '\r' )+
       { skip }
     ;

Just wish I had the time to implement it in Ruby and prove my point! Maybe in the masters thesis..

By the way, the ANTLR Book is great. If you want to learn about grammars and creating DSL’s you will love it. But be advised, you’ll hate the java trash that comes with it.

By the way Google changed their icon.

But once again, who gives a fuck? I sure don’t.

Information Retrieval using the Boolean Model in Ruby on Rails

Windows Live Mess

Não estão todos incrédulos que esteja a postar sobre isto!? Eu estou. Acabei de ler este artigo genial. Para ler, rir, reler e rir outra vez.

Fica uma pequena citação e o artigo original:

How on earth does Microsoft continue to pour massive resources into building the same frigging synchronization platforms again and again? Damn, they just finished building something called Windows Live FolderShare and I haven’t exactly noticed a stampede to that. I’ll bet you’ve never even heard of it. The 3,398th web site that lets you upload and download files to a place on the Internet. I’m so excited I might just die.

Mas não se fica por aqui. Mais aqui:

Java 6 for Mac OS X Leopard is here!!

In the most impressive development of the week I have just discovered that Java 6 was finally released for Mac OS X. I’m in complete disbelief.

Now I almost believe that IBM DB2 Express-C for mac will be released in less that a month. :P

More on this here.

Functional vs Imperative: Round 1

Imperative in python
Functional on a object oriented flavor in ruby

Note: You can do the opposite, ruby in imperative and python in functional (I’m guessing on the python part, but it’s probably true)

# choose all values from a list that are not in a matrix

# imperative in python
res = []

for value in list:
  present = False
  for mlist in matrix:
    if value in mlist:
      present = True
      break
   if not present:
     res.append(value)
# functional in ruby
res = list.select { |value| !matrix.flatten.member? value }

# restrict the matrix to values in list

# imperative strikes back
res = []

for mlist in matrix:
  current_mlist = mlist[:]
  for mvalue in mlist:
    if mvalue not in list:
      current_mlist.remove(mvalue)
  res.append(current_mlist)
# functional responds
res = matrix.map do |mlist| 
  mlist.select { |mvalue| list.member? mvalue } 
end

Problemas com a bateria do MacBook

Acabadinho de vir da garantia, onde passou um mês para trocarem a board sem que tenham conseguido resolver nenhum dos outros problemas que indiquei.

Olhem para a bateria e digam-me se isto é normal:

The mona Lisa

Nova Versão do Ubuntu – Hardy Heron

Está mesmo a sair o novo Ubuntu.

Enquanto não sai – e antecipando os habituais problemas de uma estreia, ou seja, servidores atulhados – deixo uma palavra amiga a apontar para o mirror de Software Livre do Centro ao Apoio ao Open-Source que vai ter os CD’s disponiveis para download em:

PS. Já lá esta o release candidate.

ROTD: Having fun with Ruby sort and sort_by methods

Simple sorting.

First comes a demonstration of the most common error :P
Then a simple sort
After that comes a first sort_by
And then a complete sort_by (sorted first by fname and then by lname).

>> h = [{'fname' => 'Nuno', 'lname' => 'Job'},
  {'fname' => 'Nuno', 'lname' => 'Fonseca'},
  {'fname' => 'Catarina', 'lname' => 'Pinto'},
  {'fname' => 'Nuno', 'lname' => 'Pinto'},
  {'fname' => 'Nuno', 'lname' => 'Antunes'}
]
>> h.sort
NoMethodError: undefined method '< =>' for 
{"lname"=>"Job", "fname"=>"Nuno"}:Hash
from (irb):35:in `sort'
from (irb):35
from :0
>> h.sort{|a,b| a['fname'] < => b['fname']}
=> [{"lname"=>"Pinto", "fname"=>"Catarina"},
{"lname"=>"Job", "fname"=>"Nuno"},
{"lname"=>"Fonseca", "fname"=>"Nuno"},
{"lname"=>"Pinto", "fname"=>"Nuno"},
{"lname"=>"Antunes", "fname"=>"Nuno"}]
>> h.sort_by{|p| p['fname']}
=> [{"lname"=>"Pinto", "fname"=>"Catarina"},
{"lname"=>"Job", "fname"=>"Nuno"},
{"lname"=>"Fonseca", "fname"=>"Nuno"},
{"lname"=>"Pinto", "fname"=>"Nuno"},
{"lname"=>"Antunes", "fname"=>"Nuno"}]
>> h.sort_by{|p| [p['fname'], p['lname']]}
=> [{"lname"=>"Pinto", "fname"=>"Catarina"},
{"lname"=>"Antunes", "fname"=>"Nuno"},
{"lname"=>"Fonseca", "fname"=>"Nuno"},
{"lname"=>"Job", "fname"=>"Nuno"},
{"lname"=>"Pinto", "fname"=>"Nuno"}]

Haskell $

Note: I know you will look away as soon as you see f x. Please don’t. You can see some interesting things in this post.

I was on the train with João and I was delighted to see my old friend $. I also miss composite (.) but $ is really the coolest shortcut Haskell gives a developer. So what is $?

It’s defined as:

f ($) x = f x

What does it does?

Prelude> let f x = map (succ) $ filter ( < 5 ) x
Prelude> f [4,5,7]
[5]
Prelude> let f  = zipWith ($)
Prelude> f [succ,id] [5,4]
[6,4]

Ulisses gave me the weird example. The first one was created by myself. In the first one we filter a list for numbers that are inferior to five and then we apply succ function to it. That is, we add one. :P Without $ we would have

Prelude> let f x = map (succ) (filter ( < 5 ) x)
Prelude> f [4,5,7]
[5]

So we got the parenthesis off and that always great to help make the code more readable. At least I simply love this symbol. Ulisses sample is quite more complex. First off all because it is in point-free/point-less notation. zipWith is a function that receives two lists and applies then function provided pair by pair. Like if I want to add [1,2,3] and [3,2,1] I can:

Prelude> zipWith (+) [1,2,3] [3,2,1]
[4,4,4]

Ain’t it cool? So in this function we simply apply function that goes in the first list (id and succ) to the numbers in the second. Looks easy like this doesn’t it? ;) If it doesn’t just to read it and digest it and you’ll figure it out easily.

Let code the same samples in Ruby. Unfortunately zipWith (should I commit it? :P) doesn’t exist in ruby I’ll have to work with another sample using plain zip (it’s the same as zipWith (\a b -> [a]++[b])).

irb(main):001:0> [1,2,3].zip([3,2,1])
=> [[1, 3], [2, 2], [3, 1]]

Well ruby handles this pretty well without $. We just need to do:

irb(main):002:0> [1,2,3].zip [3,2,1]

Because it’s object oriented this kind of issues don’t exist in Ruby. There are no expressions with large number of parenthesis as well. despite this I must agree that the Haskell version is far more readable than the ruby one:

irb(main):003:0> [4,5,7].select { 
  |i| i < 5 
}.map { |i| i.succ }
=> [5]

But I still miss $.I miss coding in Haskell. It’s just plain fun.

I hope that I have helped you see why languages like Haskell and Scheme do matter, and others like Python and Ruby can be both useful and fun to work with!

Site do dia

http://nao.quero.imposto.ms/

history | awk ‘{print $2}’ | sort | uniq -c | sort -rn | head

dscape@dscape:~$ history | awk '{print $2}' \
| sort | uniq -c | sort -rn | head
86 sudo
45 cd
27 ll
23 ./script/server
21 rm
17 ls
12 vim
7 startx
5 glxinfo
4 su

Contas

Há coisas que nunca são demais mostrar. Mesmo que antigas. Sobre o programa novas oportunidades:

  • 240 mil licenças de Microsoft Windows Vista Home BasicN Português DVD, 256,57€, resultam em mais de 61 milhões de Euros (61.576.800€)
  • 240 mil licenças de Microsoft Office Home and Student 2007 Português OEM, 128,51€, resultam em mais de 30 milhões de Euros (30.842.400€)

Mesmo que existisse a oferta do software, seria um presente envenenado cobrado várias vezes à economia portuguesa no futuro a médio e longo prazo.

Em http://blog.softwarelivre.sapo.pt/2007/06/05/que-casamento-e-este/

Agora as mesmas contas usando uma qualquer distribuição Linux e Open-Office:

240 mil vezes zero = zero euros (linux)

240 mil vezes zero = zero euros (open-office)

total: zero euros

poupança possível do estado: 91 milhões de euros (dos vossos bolsos)

Eu até falei de como os portugueses são tão lorpas que são roubados quando compram estes computadores e nem sequer notam. Mas esqueci-me destes pormenores fantásticos, ainda são mais roubados nos impostos que pagam por causa de promaiores como este. Peço desculpa, é que usar qualquer palavra com menor quando estam envolvidos 91 milhões parece mal.

É de referir que a Microsoft – segundo consta – fez um descontinho. Obrigado Microsoft! ;) Sempre tão simpáticos. Portanto sim provavelmente as verbas são inflacionadas, mas isso é da responsabilidade do autor do artigo e não minha. Eu só fiz as contas – com alguma dificuldade admito – do linux!

[EDIT: Vi neste post o teste de literacia digital das novas oportunidades. Peço que o façam e constatem que são todos uns iliterados porque aposto que poucos vão conseguir acabar a avaliação. E vejam lá que alguns de vocês – como eu! – são engenheiros informáticos. Que vergonha! :(]

DB2 Rocks

qs = Question.find_by_sql 
"select X.* from ots_schema.questions," +
  "XMLTABLE (\'$d/question\' passing document as \"d\" " + 
    "COLUMNS question_text VARCHAR(200)" + 
    "PATH \'question_text\') as X"
qs.first.question_text.lstrip
=> "Which of the following is the correct syntax to set the DB2COMM variable to TCPIP?\n  "

If DB2 was had a good DB2 driver and a ActivePureXML (or something adapter) it would so f*ckin rock. Just look at the sample. And the dynamic nature of ruby would enable the flexibility of xml documents.

Please IBM please. DB2 for mac and decent support on Ruby. Don’t make me write things like this no more:

# Once again fixing IBM_DB bugs the ugly way
# with_scope anyone?
add_index :'ots_schema.users', :login

or

t.column :document, :xml

Google reinvents the wheel

About porting Ruby on Rails to Javascript:

In an effort to increase developer productivity at Google, Steve tried to convince the company to adopt Rails (and consequently Ruby) as a programming language. When that fell on deaf ears (Google really does not want to increase the number of languages that must be supported by their infrastructure), Steve decided to do what any other frustrated programmer would do: he ported Rails to JavaScript. Line by line. In 6 months. Working 2000 hours. Steve is a coding stud.

From: Steve Yegge ported Rails to JavaScript

In this six months Steve could have contributed to the rails core and improved the framework to a great extent. If he found security issues like the article refers than he should have fixed them in rails. I cannot even begin to understand why he didn’t by the way. Or at least reported them.

My conclusion of seeing that google allowed a employee to waste 6 months of work because they don’t want to increase the number of languages that must be supported by their infrastructure is that Google is Dumb.

Steve seems like a smart guy so if I was told to rewrite Ruby on Rails by an employer I cannot understand why he didn’t – at the very least – refused to do so and pointed out how stupid it was to reinvent the wheel. I simply hate javascript and love ruby. I think javascript is the worst thing there is in the internet. That’s one of the reasons I decided to take a chance on XForms. Well but that’s a personal opinion and has nothing to do with the case!
The question is:

So will this bring something new to the web?

Yes! But it’s not that this wheel is great and the other was flat. It can bring something but just because Google has the power to do that, in any language they decide to use. They have the man power to go beyond what rails offer.

But does this make the decision less dumb?

No. They could do it in rails and improve a great open source product.
Or is it that hard for engineers at google to learn a new language??

has_one :through

Finally we will be able to refactor our ugly code when we have this situation (changeset 9067):

class User < ActiveRecord::Base
  has_many :channels
end
&#91;/sourcecode&#93;

&#91;sourcecode language="ruby"&#93;class Channel < ActiveRecord::Base
  belongs_to :network
  belongs_to :user
end
&#91;/sourcecode&#93;

&#91;sourcecode language="ruby"&#93;class Group < ActiveRecord::Base
  has_many :channels
  has_one :network, 
    :through => :channels,
    :conditions => ['channels.alive? = ?', true]
end

Another good news is that the RubyForge place for the OTS project was finally approved. So guess I will be doing some work on it this afternoon.

Valid and Well-formed XML Documents in Ruby on Rails

If your working with DB2 on Rails you probably need to check if the xml document is – at least – well formed.

I found a neat plugin called validates-xml that uses REXML to see if documents are well formed.

To install it simply

svn co http://validates-xml.googlecode.com/svn/trunk/ validates-xml-read-only

And copy that folder to vendor/plugins.

You can easily integrate schema validation with a validates_xml_with_schema method. But you should use REXML as it cames with the standard ruby bundle since version 1.8.

To use it simply restart your server and

validates_xml :xmldocument

That’s it!

Integração entre RSpec & TextMate

Como já disse anteriormente ando a trabalhar no CouchDB-Ruby driver. Como a coisa tem o seu nível de exigência decidi usar rspec, algo que já andava para fazer a algum tempo, de forma a melhorar a testagem do software que produzo e reduzir o tempo de implementação. Já agora aproveito para sugerir o ZenTest a quem quiser que o rspec corra em background.

Continuando: rspec é uma forma descritiva – tipo cenários em Use Case – para descrever os nossos testes. Em Ruby claro, dai o R :P

O resultado final fica assim. É catita e prático, já que evita mais uma ida a consola para escrever ‘spec filename.rb’! E é bastante parecida com a linguagem natural. Por exemplo – um dos meus primeiros testes é:

it "should connect to server and return a Server object" do
  CouchDB.connect(HOST, PORT).should 
    be_kind_of(CouchDB::Server)
end

Não fiz commit de nada porque a implementaçao anterior do CouchDB-Ruby com JSON não está completa. Portanto não vale a pena ir espreitar que não está nada lá! Em breve, espero eu, podem ver os testes completos online.

De qualquer forma se estiverem interessados em experimentar o rspec basta:

  • Instalar o rspec
    sudo gem install rspec
  • Descobrir o path onde está o ruby e o rspec. Estes comandos são capazes de ajudar:
    which ruby
    gem environment
  • Com os meus paths basta correr:
    export TM_RUBY=/usr/bin/ruby
    export TM_RSPEC_HOME=/Library/Ruby/Gems/1.8/gems/rspec-1.1.3
    cd ~/Library/Application\ Support/TextMate/Bundles/
    svn co svn://rubyforge.org/var/svn/rspec/trunk/RSpec.tmbundle
    
  • Como o (meu) terminal não gosta de exports. Caso não funcione façam:
    echo TM_RUBY=/usr/bin/ruby >> ~/.profile
    echo TM_RSPEC_HOME=/Library/Ruby/Gems/1.8/gems/rspec-1.1.3 &gt;&gt; ~/.profile
    
  • Actualizar os Bundles do TextMate
    Bundles > Bundle Editor > Reload Bundles

E pronto! Caso surjam dúvidas podem sempre consultar a documentação oficial do bundle rspec para TextMate. Que comece a diversão! Bem vá diversão é exagerar mas com rspec é pelo menos uma experiência mais agradável que o habitual quando se fala de testes.

CouchDB & Um Novo Semestre!

Bem todos os semestres faço um plano de acção do que vou fazer para além de o que é espectável de mim – ir as aulas, fazer os trabalhos, passar nos exames e ler pelo menos um livro de informática – de escolha livre – por mês.

Acredito na valorização pessoal e gosto muito de aprender coisas novas. E acredito que não existe melhor forma de o fazer que com projectos práticos!

Algumas das novidades do último semestre foram ter entrado no centro de apoio ao open-source do departamento de informática, ser eleito IBM DB2 Student Ambassador e ter entrado na melhor rede de bloggers de informática de portugal – prt.sc. Como projecto pessoal escolhi aprender – por sugestão do Ulisses CostaRuby & Ruby on Rails.

Dito isto resta uma dúvida: O que aprender este semestre?

Tenho que confessar que ando nas nuvens por terem aceite a minha colaboração no projecto CouchDB do rubyforge.

Como devem saber CouchDB é uma base de dados criada pelo Damien Katz (que trabalha agora na IBM), não relacional, desenvolvida em erlang que tem como objectivo guardar documentos e é RESTful. Os conceitos são excelentes e a forma de abordar o fault-tolerance e problemas de carga são daqueles conceitos que nos deixam a babar mortinhos por experimentar o brinquedo novo. Mas não se fica por aqui. Aconselho a lerem a wiki para terem uma noção do que é – e o que não é – o CouchDB. Só não gosto muito do facto de estar tão ligado a javascript e JSON – o primeiro porque nunca gostei muito de javascript e o segundo porque preferia yaml. Mas vá antes JSON que XML!

Outros tópicos que andam por aqui a passear – sendo que aqui é a minha cabeça – é a vontade de aprender um mínimo de Erlang e continuar o estudo de DB2 para tirar a certificação. Espero que quando acabar este semestre possa olhar para trás e sentir a mesma satisfação que sinto pelo semestre que já passou.

O Open-Source é mais barato

E ando eu a pagar propinas para isto. Mais um site feito em asp mais um belo not-so-blue-screen.

in: www.saum.uminho.pt

Eu sei, eu sei. Acontece em qualquer linguagem/framework. Mas a mim – como gajo de peculiar azar – acontece-me sempre com aspx à mistura.

Rails::ActiveRecord XQuery && DB2::Mac

Most rails developers use OS-X. Mostly because rails is built-in the latest release (Leopard) and TextMate offers a great IDE to use with Rails. Some could argue that it also works nicely on Windows but I really believe that Rails ain’t done to be used on a Windows Platform. Many articles and interviews with rails creator DHH second this statement. Rails is easy to develop in OS X and deploy in a Linux distro of your choice.

In my most recent screen-cast I explored an interesting technique of taking advantage of rails RESTful design and DB2 pureXML features to easily create a web-service that could query a relational databases with XML support (like DB2). As you must know DB2 Express-C is distributed freely and offers no limitation to home users/small companies. So it would be awesome to expand ActiveRecord to support xml elements, if a schema was provided to the database.

I’m aware that a pure xml database stategy would be a bad approach but there are situations when it simply makes sense. And in those situations one would profit greatly of two things wich are missing.

  • XML Support for ActiveRecord – in construction?
  • DB2 for Mac – will this ever exist?

Antonio Cangiano is creating a plugin that revolves around this concepts, but in a DB2 centered perspective. In my opinion it would be best if the rails plugin worked not only for DB2 but for any database adapter with XML support – as long as such is provided.

Let me give you a sample. Imagine that you have a database model for translating you rails application. It could be something like:

Languages

  • ID, int
  • DOCUMENT, XML

Imagine that the xml file is

<language isoname="pt-PT">
  <hello>Olá</hello>
  <bye>Até a próxima!</bye>
</language>
(...)

If this makes sense in your application then you could easily do something like register your model to observe (see observer design pattern) the session[‘language’] for changes and, if it’s changed, it would get all the XML for that language – it would fall back to default if such was not available – and create the hash with the values. The problem with this approach – besides making no sense for the internationalization problem! – is that in the observer model you would have to:

Language.find :first

And fetch the whole xml and then process it. If the XML document has 10MB, it would take some time. With XQuery support on ActiveRecord we could simply

Language.find :first, 
  :xcondition => ["//language[@isoname==?]", 
    session['language']]

Or, if we simply wanted to say hello in many languages – like flickr in their first page – we could simply

Language.find :first, :xcondition => '//hello'

There are just two problems that prevent rails developers from being able to do this kind of things. And those are the lack of XQuery abilities in ActiveRecord and the fact that Mac developers cannot use DB2.

METS Standard with IBM DB2 Express C using XForms as user-interface and Ruby on Rails as a Rest Web-services

HIGH QUALITY VERSION DOWNLOAD HERE

Well, here is the long promised screen-cast. The amount of topics covered is simply huge. To get you ready for the screen-cast I prepared some other more introductory screen-cast as well as some articles on these subjects. I’m sorry that I don’t have the time to document the REST, but I really advice to invest some time learning it as it’s a very pragmatic way of delivering high quality web services.

I strongly advice you to download this screen-cast from rapidshare as both Youtube and Google Videos quality is really awful. You can download it from here.

This work was really fun to do. So I hope to have the opportunity to develop it further and manage nested rest routes like /mets/1/agents to return the agents of the first submission information package (sip) using some cool DB2 pureXML features. I really feel that with a good plugin to help users take full advantage of DB2 pureXML features and a little of imagination this web-service could be of some use.

I also expect to complete the xforms model as it is not indexing a fileptr to each category when such is selected. I hope to implement this soon enough.

Here are the associated resources I developed:

And here are the other two screencasts I produced to introduce you to XForms and METS:

I also advice you to take a look at this articles. All of them where very helpful to my work.

XmlSimple?

>> xml_plain = %q(<p>Just a <strong>p</strong> on bold</p>)
=> "<p>Just a <strong>p</strong> on bold</p>"
>> xml_hash = XmlSimple.xml_in xml_plain,
  'ForceArray' => true
=> {"strong"=>["p"], "content"=>["Just a ", " on bold"]}
>> xml_plain2 = XmlSimple.xml_out xml_hash, 
  'RootName' => 'p'
=> "<p>\n  <strong>p</strong>\n  <content>Just a </content>\n  <content> on bold</content>\n</p>\n"

Não querendo ser malvado com quem fez esta biblioteca acho que o mínimo expectável para uma operação de marshall/unmarshall é que seja reflexiva. Lá vou eu ler documentação para descobrir como se ensina o XMLSimple – nome curioso não é? – a ser o que nunca deveria deixar de ser. Reflexivo.

Já agora se alguém já programou web services em rails e sabe como transformar os params em xml de uma forma melhor, let me know!

Devolvam as passwords aos vossos utilizadores com Ruby on Rails 2.0

Uma coisa que me chateia imenso nas webapplications de trazer por casa – traduzindo aquelas que são feitas por colegas meus ou por outros amadores pela web fora – é o facto de guardarem quase sempre as passwords na base de dados em plaintext. Acho que não tem o direito de saber a password que uso, nem que a use exclusivamente nesse site (como é o caso)

Assim, se quem fez a aplicação for mal intencionado, pode simplesmente obter a vossa password escrevendo

select * from users where user.username = 'nick'

Mas mesmo que não sejam mal intencionados, outra pessoa pode aceder a base de dados. Ou podem simplesmente não se ter protegido contra sql injection. Há um milhão de razões pelas quais nunca se deve guardar as password em plaintext, sendo que a principal deles é o facto da password não ser vossa. É do utilizador. E isso faz toda a diferença! Não acreditam em mim certo? Estou a exagerar.

Convido-os a visitar esta página

Agora procurem por ‘qualquer_coisa. O resultado é

  • Pesquisa por “\’qualquer_coisa”:

Este \’ é importantíssimo pois significa que a página se esta a proteger contra ataques de sql injection. Caso contrario um hacker podia, com alguma sorte, obter informação privilegiada que estava contida nessa base de dados.

Mas ninguém faz um erro destes, certo? Errado. Vamos ao google e procurem php em páginas de Portugal. O sexto resultado, e único que testei, é a associação nacional de farmácias. Se procurarem por ‘qualquer_coisa o resultado é um não tão surpreendente erro. Isto é um exemplo de milhares, alguns dos quais onde vocês inserem as vossa password (e sabe-se lá o que mais) diariamente. Não se sentiam melhor se soubessem que nessa base de dados não está a vossa password?

Mas voltando ao assunto, a táctica que vou usar consiste em usar um algoritmo de one way hash chamado SHA. O utilizador, quando se regista no site, insere a sua password. Esta é processada (num processo que se chama de digest) para uma hash que contém não a password mas sim a encriptação dessa password em SHA. Como SHA é um algoritmo de one-way-hash, é fácil obter a hash única para qualquer palavra mas quase impossível de decifrar no sentido inverso. Para ser suficiente, mas não é.

Comecemos por ir para a consola do rails. Entrem no terminal e naveguem até onde tem a vossa Ruby on Rails web application. Agora escrevam.

./script/console

Quando lá estiverem podem verificar que aplicando este algoritmo a palavra porto obtemos sempre a mesma resposta.

>> password = 'porto'
=> "porto"
>> Digest::SHA256.hexdigest(password)
=> "01735c5ff1608734e4c38449a00b74bb9a8d5423ed548238da70178e9e803483"
>> Digest::SHA256.hexdigest(password)
=> "01735c5ff1608734e4c38449a00b74bb9a8d5423ed548238da70178e9e803483"

Não sei se repararam mas o nosso utilizador usa uma palavra pass muito fraca. Isto vai fazer a diferença, por o hacker pode obter a password facilmente se tiver a hash.

Como? Sim eu disse que era muito difícil crackar o SHA, alias não conheço ninguém que o tenha feito. Ninguém conhece :P

Mas o hacker pode pegar numa lista de palavras comuns nas passwords e, para cada uma das palavras associar a hash correspondente. Agora se tiver a vossa hash pode comparar com o dicionário que criou descobrir algumas das passwords da base de dados, aquelas que estavam na lista de palavras comuns.

Para resolver este problema usamos um salt. Um salt é também uma palavra (como a vossa password) que sera usada para evitar esta técnica. é mais simples mostrar que explicar, e por isso mesmo:

>> password = 'porto'
salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
>> salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
=> "19L6gVcD"
>> salt = [Array.new(6){rand(256).chr}.join].pack("m").chomp
=> "CqEVe632"
>> password = 'porto'
=> "porto"
>> Digest::SHA256.hexdigest(password + salt)
=> "c017e1c49096149097050c76f0406dce9245058e0d..."

De certeza que o hacker não vai procurar pela string portoCqEVe632 e, portanto, os nossos utilizadores estão seguros. Caso queiram saber um pouco mais sobre o que se passa no criação do salt, e que é aquele pack(‘m’) peçam nos comentários e eu escrevo um artigo sobre isso. Senão nunca mais saio daqui! :P.

Agora surge a pergunta, como usar esta informação em rails. Simples.

Vamos começar por criar um projecto:

rails secureusers && cd secureusers

Agora precisamos de criar o modelo de utilizador

./script/generate model User username:string \
  password_hash:string password_salt:string
rake db:migrate

Abram o vosso User.rb model, apaguem o que lá tem, e insiram o seguinte código

require 'digest/sha2'
class User < ActiveRecord::Base
# usei o attr_accessible em vez do
# attr_protected :password_hash, :password_salt
# porque é boa prática em Rails usar o enabled para 
# os campos acessíveis e não o contrário.
#
# Imaginem que tinham um campo isAdmin e se 
# esqueciam de por no protected.
# Ao dizerem que enabled só o :username impedem 
# o acesso a todo e qualquer outro campo,
# excepto aqueles que foram explicitamente 
# escolhidos por vocês.
  attr_accessible :username
  attr_accessor :password

  def before_save
    unless password.blank?
      salt = &#91;Array.new(6){rand(256).chr}.join&#93;.pack("m").chomp
      self.password_salt, self.password_hash = salt,
      Digest::SHA256.hexdigest(password + salt)
    end
  end

  def self.authenticate(username, password)
    user = User.find :first,
        :conditions => ['username = ?', username])
      if user.blank?
        raise "O utilizador não existe"
      elsif Digest::SHA256.hexdigest(password + user.password_salt) != user.password_hash
        raise "A autenticação falhou"
      else
        user
      end
  end
end

Usei o attr_accessible em vez do protected porque considero esta uma boa practica. Prefiro dizer quais os campos acessíveis que quais os que se deve proteger. Assim não corro o risco de me esquecer de proteger algum campo. E os que são para ver nota-se bem quando faltam :P Podem ler mais sobre isto aqui.

Depois de toda esta explicação o código deve ser muito facil de entender. Até para quem não sabe Ruby. Vamos testar?

>> nuno = User.new
=> #<user id: nil,
  username: nil,
  password_hash: nil,
  password_salt: nil,
  created_at: nil,
  updated_at: nil>
>> nuno.username = 'nuno'
=> "nuno"
>> nuno.password = 'porto'
=> "porto"
>> nuno.save
=> true
>> nuno
=> #</user><user id: 1, 
  username: "nuno",
  password_hash: "c490ea11d96be24ece2ca0dba11d84fc9b...",
  password_salt: "V+b7Sqjh",
  created_at: "2008-02-12 19:28:54",
  updated_at: "2008-02-12 19:28:54">

E agora autenticar:

User.authenticate 'nuno', 'porto'
=> #</user><user id: 1, 
  username: "nuno",
  password_hash: "c490ea11d96be24ece2ca0dba11d84fc9b...",
  password_salt: "V+b7Sqjh",
  created_at: "2008-02-12 19:28:54",
  updated_at: "2008-02-12 19:28:54">

Fixe. É so por no session[:user] ;) Para finalizar aconselho-vos vivamente a suportarem open-id para o processo de autenticação dos utilizadores. Existem plugins muito bons que o fazem, e podem ler mais sobre open-id no seu fantástico guia supersónico.

Working different models in the same form on Ruby on Rails

Well it’s been a heck of a week, loving somethings on rails and hating others :P

Anyway I had a problem with working with different models on a form. If you are having the same kind of issues I’ll give you some pointers:

My notes file is so big I think I’ll never solve all those issues. *g* Anyway another pointer I can give you is to check out haml. I didn’t used it but it sure is simpler than html.

This version of RMagick was created to run with ImageMagick 6.3.3 but ImageMagick 6.3.8 is in use

A paciencia tem os seus limites e vou dormir. Se entretanto alguém descobrir a solução para isto peço-lhe o favor de me deixar nos comentários.