ImageMagick to the rescue:
for img in *.gif ; do convert $img -colorspace Gray -colors 16 grey_$img ; done
Ok - so not really one line, but almost :-)
And this is what it looks like afterwards in my file explorer:
for img in *.gif ; do convert $img -colorspace Gray -colors 16 grey_$img ; done
title Ubuntu 8.04.1 Installer (hd0,0)(I actually first tried the vmlinuz and initrd.gz I found in the installer directory, but that insisted on a CD, and I did not want to try faking that with a raw partition, so I changed to the netboot option in the text above.)
kernel (hd0,0)/boot/install/netboot/ubuntu-installer/i386/linux vga=normal ramdisk_size=14972 root=/dev/rd/0 rw --
initrd (hd0,0)/boot/install/netboot/ubuntu-installer/i386/initrd.gz
gs -r300x300 -sDEVICE=tiffgray -sOutputFile=ocr_%02d.tif -dBATCH -dNOPAUSE inputfile.pdf
#!/usr/bin/env ruby
(ARGV.length>0) || puts("usage: ./ocr.rb file1.pdf <file2.pdf> ...") || exit(0)
$basedir=Dir.getwd
ARGV.grep(/\.pdf/i).each do |pdf|
dir = pdf.gsub(/\.pdf/,'')
dir += '_OCR'
dir += '.dir' if(dir == pdf)
Dir.mkdir(dir) unless(File.exist?(dir))
Dir.chdir(dir)
puts "Extracting pages from PDF: #{pdf}"
system "gs -r300x300 -sDEVICE=tiffgray -sOutputFile=ocr_%02d.tif -dBATCH -dNOPAUSE \"#{$basedir}/#{pdf}\""
tiff_pages = Dir.new('.').grep(/^ocr.*\.tif$/).sort
puts "Running tesseract OCR on pages: #{tiff_pages.join(', ')}"
tiff_pages.each do |page|
page_base = page.gsub(/\.tif.*/,'')
print "#{page_base} "
system "/usr/local/bin/tesseract #{page} #{page_base}"
end
Dir.chdir($basedir)
ocr_pages = Dir.new(dir).grep(/^ocr.*\.txt$/).sort
if ocr_pages && ocr_pages.length>0
puts "Created OCR result pages: #{ocr_pages.join(', ')}"
archive = "#{dir}.zip"
puts "Creating archive of result pages: #{archive}"
system "zip -r \"#{archive}\" #{ocr_pages.map{|p| "\"#{dir}/#{p}\""}.join(' ')}"
else
puts "No OCR result pages found"
end
puts ""
end
rails -d mysql myapp
cd myapp
rake db:create # you might need to edit config/database.yml first to match your db installation
script/plugin install http://elitists.textdriven.com/svn/plugins/acts_as_state_machine/trunk
# I needed to use trunk, as other versions have a missing const RailsStudio error
script/plugin source http://svn.techno-weenie.net/projects/plugins
script/plugin install restful_authentication
# obviously these last two lines can be combined
script/generate authenticated user sessions --include-activation --stateful
# This will create the users model and the users and sessions controllers.
map.resources :users, :member => {
:suspend => :put,
:unsuspend => :put,
:purge => :delete
}
map.resource :session
map.activate '/activate/:activation_code', :controller => 'users', :action => 'activate'
map.signup '/signup', :controller => 'users', :action => 'new'
map.login '/login', :controller => 'sessions', :action => 'new'
map.logout '/logout', :controller => 'sessions', :action => 'destroy'
map.forgot_password '/forgot_password', :controller => 'users', :action => 'forgot_password'
map.reset_password '/reset_password/:code', :controller => 'users', :action => 'reset_password'
map.account '/account', :controller => 'users', :action => 'account'
config.active_record.observers = :user_observerThis allows for activation emails to be sent.
t.column :password_reset_code, :string, :limit => 40
t.column :is_admin, :boolean, :default => false
rake db:migrate
include AuthenticatedSystem
self.current_user = @userThis allows us to add further processing of the user registration request, by adding a create.html.erb view and email activation.
redirect_back_or_default('/')
<fieldset>
<legend>New account</legend>
<p>Instructions for activating your account
have been sent to <%=h @user.email %>
If this address is incorrect, please
<%= link_to 'signup', signup_path %>
again. If you do not receive the email
soon, please check your spam filter.</p>
</fieldset>
def user_logged_in?
session[:user_id]
end
def user_is_admin?
session[:user_id] && (user = User.find(session[:user_id])) && user.is_admin
end
<%= link_to 'Forgot password?', forgot_password_url %>
<div style="position: absolute; right: 0px; top: 0px; height: 20px;">
<% if user_logged_in? %>
<%= link_to 'Logout', logout_url %>
<% else %>
<%= link_to 'Signup', signup_url %>
| <%= link_to 'Login', login_url %>
<% end %>
protected
# Protect controllers with code like:
# before_filter :admin_required, :only => [:suspend, :unsuspend, :destroy, :purge]
def admin_required
current_user.respond_to?('is_admin') && current_user.send('is_admin')
end
before_filter :admin_required, :only => [:suspend, :unsuspend, :destroy, :purge]
def account
if logged_in?
@user = current_user
else
flash[:alert] = 'You are not logged in - please login first'
render :controller => 'session', :action => 'new'
end
end
# action to perform when the user wants to change their password
def change_password
return unless request.post?
if User.authenticate(current_user.login, params[:old_password])
# if (params[:password] == params[:password_confirmation])
current_user.password_confirmation = params[:password_confirmation]
current_user.password = params[:password]
if current_user.save
flash[:notice] = "Password updated successfully"
redirect_to account_url
else
flash[:alert] = "Password not changed"
end
# else
# flash[:alert] = "New password mismatch"
# @old_password = params[:old_password]
# end
else
flash[:alert] = "Old password incorrect"
end
end
# action to perform when the users clicks forgot_password
def forgot_password
return unless request.post?
if @user = User.find_by_email(params[:user][:email])
@user.forgot_password
@user.save
redirect_back_or_default('/')
flash[:notice] = "A password reset link has been sent to your email address: #{params[:user][:email]}"
else
flash[:alert] = "Could not find a user with that email address: #{params[:user][:email]}"
end
end
# action to perform when the user resets the password
def reset_password
@user = User.find_by_password_reset_code(params[:code])
return if @user unless params[:user]
if ((params[:user][:password] && params[:user][:password_confirmation]))
self.current_user = @user # for the next two lines to work
current_user.password_confirmation = params[:user][:password_confirmation]
current_user.password = params[:user][:password]
@user.reset_password
flash[:notice] = current_user.save ? "Password reset successfully" : "Unable to reset password"
redirect_back_or_default('/')
else
flash[:alert] = "Password mismatch"
end
end
class UserMailer < ActionMailer::Base
def signup_notification(user)
setup_email(user,'Please activate your new account')
@body[:url] = "#{SITE}/activate/#{user.activation_code}"
end
def activation(user)
setup_email(user,'Your account has been activated!')
@body[:url] = "#{SITE}/"
end
def forgot_password(user)
setup_email(user,'You have requested to change your password')
@body[:url] = "#{SITE}/reset_password/#{user.password_reset_code}"
end
def reset_password(user)
setup_email(user,'Your password has been reset.')
end
protected
def setup_email(user,subj=nil)
recipients "#{user.email}"
from %{"Your Admin" <bounce@yourdomain.com>}
subject "[#{SITE}] #{subj}"
sent_on Time.now
body :user => user
end
end
def forgot_password
@forgotten_password = true
self.make_password_reset_code
end
def reset_password
# First update the password_reset_code before setting the
# reset_password flag to avoid duplicate mail notifications.
update_attributes(:password_reset_code => nil)
@reset_password = nil
end
# Used in user_observer
def recently_forgot_password?
@forgotten_password
end
# Used in user_observer
def recently_reset_password?
@reset_password
end
# Used in user_observer
def recently_activated?
@activated
end
protected
def make_password_reset_code
self.password_reset_code = Digest::SHA1.hexdigest( Time.now.to_s.split(//).sort_by {rand}.join )
end
def after_save(user)
UserMailer.deliver_activation(user) if user.recently_activated?
UserMailer.deliver_forgot_password(user) if user.recently_forgot_password?
UserMailer.deliver_reset_password(user) if user.recently_reset_password?
end
sendmail -f admin@mydomain.com me@myaddress.com
Subject: test
Hello, world!
.

For a more specific Ruby-2-Java comparison, see the extract in ComputerWorld of the book ‘Rails for Java Developers.’ This is a nice soft intro to Ruby for Java developers. However, while my snippets are not as complete, I think they are more interesting and relevant to me, of course. And I hope they will be of interest to others too.
My other brother and his wife have recently moved to the remote north west of Australia and started blogging from there too. Interesting place. I'd love to visit, but damn it's far away!Wow! I could spend hours poring over this incredible mine of information. But I better save the rest for another day :-)
Over the last few years I've begun using the phrase "the perception of control" to describe a phenomenon in company decision making I've seen unpleasantly often. I view it somewhat as a successor to my previous pet phrase "un/informed decision making" and coupled to the phrase "the illusion of efficiency" which I’ve also enjoyed using.
Un/informed decision making
I'm pleased to say I've spent most of my career working for small startup companies, where necessity requires that decision making is done by the same people that actually do the work. This usually leads to relatively well informed decision making. However, at least once I have worked for a large company that was structured with vertical silos such that decisions were made by managers that usually knew very little about the subject on which they needed to take the decision. Generally they also didn't have the time or inclination to educate themselves, or at least talk to the 'people on the ground' who actually knew something. Take a look at a recent posting on this subject by an IT professional forced to follow IT decisions taken by his IT-illiterate boss: When servers crash and burn
This vertical silo structure has a secondary effect when large companies try to increase efficiency by creating narrow, specialized roles, which leads me to my second phrase:
The illusion of efficiency
Back in the same large company, I had the rather illuminating experience of being part of a 5 man international team that took 6 months to install a printer. Yes, you heard me right, six months and 4 teleconferences simply to install a printer. This amazing level of extreme inefficiency was the direct result of IT projects designed to increase company operational efficiency through specialization. The point was that if each individual only did one specific task, they would do it faster, perhaps as much as 20% or even 30% faster than someone switching context between several tasks. The end result: IT support was located in Asia, core networking in Germany, Windows domain management in Norway, hardware requisition in Belgium and Project management in Scotland. With business management in California, things could have been even more complicated, but luckily they were only required in one of the meetings. Had we had an onsite IT individual handling all the various IT-related tasks, the project would have taken a couple of hours at most.
More recently I've been in discussions with my current management on the subject of software development efficiency. They can see that 20% to 30% efficiency gains might be possible through the reuse of software code components across the company product lines. I have argued that any fractional operational cost gains will be offset by dramatically increased time-to-market losses. We're not talking 6 months for a 2 hour project, like my previous example, but we're certainly talking about taking 6 month software projects and scaling them up to years. This problem is nothing new. Software companies have battled with these issues for decades, and many books have been written on the subject. One of the earlier ones is ‘The mythical man-month’ covering related issues, but more recently the flood of Agile development books, like ‘Lean software development’, ‘Extreme programming’ and of course the entire ‘pragmatic programmer’ series.
Drawing from experience I can say that for years I too believed in trying to increase software development costs through increased code re-use, or the sibling concept:- coupling existing software projects together to prevent re-inventing the wheel. However, retrospective analyses of such projects lead me to a few ‘startling’ conclusions:
These observations have made me a natural believer in much of the new Agile development methodology that is such a hot topic these days. Clearly there is a growing body of software developers that no longer believe in ‘silo’d’ projects with ‘uninformed decision making’ and ‘the illusion of efficiency’ driving project decisions. I’m certainly one of them, but unfortunately many managers are not in agreement. This leads me to the main point of this article:
The perception of control
In a small startup company, where there are few people interacting, people generally have a high level of ‘control’ over their environment, colleagues or projects. This is a natural consequence of the fact that any decision maker needs to talk to very few people, if any, to take an “informed decision”. Quite often the decision maker is actually the person that knows the most, and the person that needs to follow through with actions. However, as companies grow, the number of employees increases and jobs become more specialized, decision makers start ending up in the position where they no longer know enough to make an informed decision. Things can go in two ways:
Paradoxically enough, those that are most dictatorial are exposed soonest and often thrown out by the first controlling VC around the corner, while those that try hardest to do it right and delegate are those that end up maintaining the dictatorial approach for longest. But it cannot last. Dictators are always overthrown.
So, how do you tell the difference between true delegation and dictators operating with the ‘perception of control’? Well it’s not as hard as you might expect. There are a few rather simple things to look for:
I've just had the opportunity to compare voice quality with back-to-back calls on GSM, JabPhone and SkypeOut. JabPhone wins easily, but there are provisos.
First, the test:
The results:
Because JabPhone has the best basic voice quality, I rank it best overall for longer term potential, since the remaining problems are all things that can presumably be addressed. The service is currently advertised as version 0.2, so I expect it will be much better by version 1.0.
Of course, it goes without saying that these opinions are entirely subjective. I’ve always found Skype voice quality to be a bit weird, even back in the days when I did not have the occasional ‘really-bad’ Skype calls (today’s was a good call). I know of others that disagree and find Skype to be great.
When all is said and done, although I have access to, and use, three different VoIP systems (jabber/GoogleTalk/JabPhone, Skype/SkypeOut and a SIP service with x-lite), I still use Skype the most. So, no matter what I think of the voice quality, the continued convenience and professionalism of the service still keeps them in the winning seat as a service (for now :-).
Next to test: compare some other systems like www.jajah.com and the standard SIP service I mentioned above
