Mostrando entradas con la etiqueta programación. Mostrar todas las entradas
Mostrando entradas con la etiqueta programación. Mostrar todas las entradas

domingo, 6 de diciembre de 2009

CruiseControl

CruiseControl es una herramienta de integración continua escrita en, y para, ruby. Su finalidad básica es la de alertar a los miembros de un proyecto software cuando un cambio en el repositorio de control del código fuente (como svn) rompe dicho proyecto. En el caso de RoR, lo que hará periódicamente será la ejecución de los test de la aplicación, informando del resultado.

Es muy fácil de usar. Basta con descargarlo (es un mini-proyecto RoR), añadirle nuestro proyecto (indicando el repositorio del código fuente), y arrancarlo. Por defecto arranca en el puerto 3333, y si accedemos nos encontraremos algo como esto. Además, podemos integrar rcov en cruisecontrol y obtener información del code coverage de nuestro proyecto.

Usando rcov desde cuisecontrol

Para que CruiseControl nos facilite información sobre el Code Coverage, necesitamos:
  1. Gema rcov ('sudo gem install rcov'). Comprobamos ejecutando 'rcov' en el terminal.
  2. Plugin rails_rcov ( './script/plugin install http://svn.codahale.com/rails_rcov' --> Doc: http://agilewebdevelopment.com/plugins/rails_rcov)
  3. Añadir en lib/tasks/ el fichero cruise.rake con el siguiente contenido:

# Set the artifacts dir for development
ENV['CC_BUILD_ARTIFACTS'] ||= File.expand_path("#{RAILS_ROOT}/metrics")
ENV['RAILS_ENV'] = 'test'

# This hack is needed because db:test:purge implementation for MySQL drops the test database, invalidating
# the existing connection. A solution is to reconnect again.
def reconnect
require 'active_record' unless defined? ActiveRecord
configurations = ActiveRecord::Base.configurations
if configurations and configurations.has_key?("test") and configurations["test"]["adapter"] == 'mysql'
ActiveRecord::Base.establish_connection(:test)
end
end

desc 'Continuous build target'
task :cruise do
# Add local user gem path, in case rcov was installed with non-root access
#ENV['PATH'] = "#{ENV['PATH']}:#{File.join(Gem.user_dir, 'bin')}"

puts
puts "[CruiseControl] Build environment:"
puts "[CruiseControl] #{`cat /etc/issue`}"
puts "[CruiseControl] #{`uname -a`}"
puts "[CruiseControl] #{`ruby -v`}"
`gem env`.each_line {|line| print "[CruiseControl] #{line}"}
puts "[CruiseControl] Local gems:"
`gem list`.each_line {|line| print "[CruiseControl] #{line}"}
puts

out = ENV['CC_BUILD_ARTIFACTS']
mkdir_p out unless File.directory? out if out

if File.exists?(Dir.pwd + "/config/database.yml")
if Dir[Dir.pwd + "/db/migrate/*.rb"].empty?
raise "No migration scripts found in db/migrate/ but database.yml exists, " +
"CruiseControl won't be able to build the latest test database. Build aborted."
end

# perform standard Rails database cleanup/preparation tasks if they are defined in project
# this is necessary because there is no up-to-date development database on a continuous integration box
if Rake.application.lookup('db:test:purge')
Rake::Task['db:test:purge'].invoke
end
if Rake.application.lookup('db:migrate')
reconnect
Rake::Task['db:migrate'].invoke
end
end

if RUBY_VERSION == '1.8.7'
puts '!!!!!! Skipping rcov on Ruby 1.8.7'
Rake::Task["test:units"].invoke
Rake::Task["test:functionals"].invoke
else
ENV['SHOW_ONLY'] = 'models,lib,helpers'
Rake::Task["test:units:rcov"].invoke
mv 'coverage/units', "#{out}/unit test coverage" if out

ENV['SHOW_ONLY'] = 'controllers'
Rake::Task["test:functionals:rcov"].invoke
mv 'coverage/functionals', "#{out}/functional test coverage" if out
end
end

Para probar que funciona correctamente y que cruise-control no va a fallar, podemos probar a ejecutar:
rake cruise

martes, 22 de julio de 2008

Spam

Se denomina spam o correo basura a aquellos mensajes no solicitados, habitualmente de tipo publicitario, enviados en grandes cantidades (incluso masivas) que perjudican de alguna o varias maneras al receptor.
Hoy día, contamos con muchos y muy buenos filtros anti-spam. La mayoría de ellos están basados en el texto del email. Se lee de manera automática la cabecera y cuerpo del mensaje y mediante algunas técnicas de clasificación se lleva a cabo de forma automática una clasificación de dicho email (por ejemplo, podría verse el número de veces que aparece la palabra "viagra"). Normalmente, aquel que es considerado como spam viene colocado en una carpeta distinta a la bandeja de entrada, por ejemplo la carpeta spam.

Los spammers han optado por una nueva forma de spam con el objetivo de saltarse los filtros anteriormente comentados. Básicamente consiste en añadir el texto del mensaje a una imagen, y añadir dicha imagen en el email. De esta forma, no habría texto de forma legible según los métodos anteriormente dichos.
Para tratar de solucionar este nuevo problema, existen programas como SpamAssassin (bajo licencia Apache 2.0) que usan otras técnicas para la clasificación. En particular, para el problema anteriormente propuesto, bastaría con usar un OCR y extraer todo el texto de la imagen para posteriormente pasarlo a un clasificador como los anteriormente mencionados.

Pero los spammers han ido más allá. Ahora tratan de ocultar el texto en imágenes y además tratan de ofuscarlo. Es decir, tratan de meter el texto en imágenes y añaden técnicas para que un programa OCR no sea capaz de extraer dicho texto (como puede ser el uso de fondos de colores no uniformes, trazos de lineas por encima del texto, texto cursivo, etc.).
Para ello, en colaboración con el grupo de investigación P.R.A. de la universidad de Cagliari he desarrollado un plugin para el programa SpamAssassin basado en el trabajo que llevan desarrollando bastante tiempo. Básicamente se trata de extraer ciertas características de la imagen (no de extraer el texto) como el número de colores (una imagen de spam normalmente tendrá muchos menos colores que una imagen legítima...) y una vez normalizados los datos y habiendo entrenado previamente un classificador SVM (Support Vector Machine) con kernel RBF (Radial Basis Function) se procede a la clasificación.
Los resultados obtenidos han sido bastante buenos. No solo basta con tener un número alto de aciertos y bajo de fallos, sino que en este caso debemos tratar de minimizar los falsos positivos (clasificar el email como spam siendo legítimo) aunque a costa de ello perdamos eficacia en los falsos negativos (clasificar el email como legítimo siendo SPAM). A ninguno de nosotros nos gustaría que se clasificase como spam un email que no lo es, ¿vedad? Aunque alguno que sí lo sea lo tengamos que borrar de la bandeja de entrada...

Podéis ver más sobre el trabajo realizado aquí.