Thursday, December 27, 2007

Ubuntu's little upstart

One of my customers has a mix of Debian and Ubuntu servers installed in their network with a treasure trove of distribution versions from Debian GNU/Linux 3.0 (Woody) to Ubuntu 7.10 (Gutsy Gibbon). They have a fair amount of custom debs which need to coexist on these servers.

While installing a new Gutsy box I noticed that several of the in-house debs were failing while trying to modify /etc/inittab (our preferred way to keep things running that should never die). This was quite confusing to me as the last Ubuntu server I worked with was Ubuntu 6.06.1 LTS (Dapper Drake) which did not exhibit this weirdness.

Down the rabbit hole
Imagine my amazement when I tried to find /etc/inittab and it was completely missing! My reality reset, I checked again and it was still missing.

At first I thought some critical package (sysvinit in the versions of Ubuntu I know) was somehow missing after the base install. I jumped on the Ubuntu packages site and did a search for 'sysvinit'. Sure enough, there it was but the file list showed no inittab.

Suddenly I felt like I a four year old whose mommy had lost them at the Mall.

Further down the spiral
The file list did however list a bunch of items that referred to something called 'upstart-compat-sysv'. Browsing to this package listed the follwoing description for the package:

This package contains compatibility tasks and utilities that emulate the behaviour of the original sysvinit package, including runlevels, and ensures that the initscripts in /etc/rc*.d are still run.

OK. I faintly hear someone announcing that my mother is looking for me at the Mall's security office.

So if upstart-compat-sysv _emulates_ the original sysvinit, then what has _replaced_ it?

Upstart, show thy face
Google provided me with this link that points to the Ubuntu upstart page which went a long way towards uniting me and my mommy:

Upstart is an event-based replacement for the /sbin/init daemon which handles starting of tasks and services during boot, stopping them during shutdown and supervising them while the system is running.

It was originally developed for the Ubuntu distribution, but is intended to be suitable for deployment in all Linux distributions as a replacement for the venerable System-V init.

Sounds even more pervasive than a simple missing iniitab!

Features:
  • Tasks and Services are started and stopped by events
  • Events are generated as tasks and services are started and stopped
  • Events may be received from any other process on the system
  • Services may be respawned if they die unexpectedly
  • Bi-directional communication with init daemon to discover which jobs are running, why jobs failed, etc.
To my amazement upstart has been turned on by default since Ubuntu 6.10 (Edgy Eft) which explains why I was totally in the dark (but upstart was seemingly nothing new to everyone that had been following the normal upgrade path).

So, upstart was not only superseding everything we were trying to do with inittab but also changed the way one interacts with scripts via /etc/event.d.

Why reinvent the wheel?
With the Ubuntu decision to move to the 2.6 kernel, and all the hotplug facilities it provides, they were left with several problems in Dapper. The kernel could now completely cope with hardware coming and going but that had a knock-on effect in that there was now no way to guarantee that particular devices were available at particular point in the boot process.

For example: Dapper cannot mount USB disks in /etc/fstab because it is not guaranteed that the block device exists at the point in the mount process where that happens.

Several other reasons are also provided on the Ubuntu site.

At first, the team decided to look at the available alternatives in third party projects such as Solaris SMF, Apple's launchd, the LSB initserv/chkconfig tools and initNG. None of these met the design criteria that the team had set out for themselves and in true OSS style they decided to roll their own.

The design and implementation documentation is pretty clear so I won't repeat it here.

Epilogue
In the end I simply had to add some logic to the custom debs to check if the system was running upstart and do The Right Thing(TM) (using upstart if it was available or falling back to using inittab) based on that. That amounted to dropping a relevant file in /etc/event.d/ for every server that we previously ran from inittab for systems that were using upstart.

Further Reading



Friday, October 5, 2007

Func it up with JavaScript

UPDATE: David Pollak has a great introduction to FP via JavaScript and Ruby.

Using functional programming paradigms in JavaScript are non-existent, clumsy, verbose and difficult to read in most cases. "Oliver Steel":http://osteele.com/ has built an excellent little library that does the grunt work for you when trying to get your func on.

To Func || ! Func
Most people go about their imperial programming days without a thought of functional programming techniques and how they can be applied to their daily problems. In most part this is due to the inherent difficulties with _doing_ functional programming in their tool of choice.

I urge you to do some further investigation (read Why Functional Programming Matters) into functional programming techniques even if you think you'll never use them anywhere. This is not intended to be an exercise in (academic) pointlessness but to place you outside of your comfort zone and expand your thinking across different domains. The depth of knowledge gained from this will enable you to solve problems from a larger pool of tools (sometimes allowing you to bring functional programming paradigms to bare on a problem or simply augmenting your existing tools for a more efficient or elegant solution to problems).

Learn to get your Func on!

From a pure functional programming language perspective this approach to problem solving offers the following advantages over the imperative and OOP approaches:
  • No (re-)assignment
  • No side effects
  • No flow of control
Functional calls can therefore have no other effect that to compute its result. In a pure functional language there are no assignments statements. Once you assign a value to a variable the variable never changes. In this sense variables in a functional language have more in common with algebraic variables that the normal programming stock we're used to.

At first this seems like a debilitating restriction but after giving your brain some time to expand you'll find that this simple restriction eliminates one of the largest sources of bugs in programming and makes the order of execution irrelevant as no side-effect can change the value of an expression and it can be evaluated at any time.

Gone are the days of worrying about orchestrating the flow control of your program. Your programs are now referentially transparent because expressions, variables and their values can be freely evaluated and replaced at any time.

Elements of Func
From a strict academic sense functional programming refers to programs that has a main body which is a function that receives it's input as its arguments and delivers the output/transformation as it's result.

So far this definition should not seem too foreign to most people that have worked with c/c++. Where this departs from the general imperative meme is that the main function is generally defined in terms of other functions, which in
turn are defined in terms of still more functions, until at the lowest level the functions are first-class citizens (language primitives).

These functions are much like ordinary mathematical functions (in that the same input will always deliver the same output).

Higher-order programming (HOP), function level programming (FLP) and partial function application (PFA) are all styles used in functional programming.

Programming Transcendence
HOP is the ability to use functions as values, in other words you can pass functions as arguments to other functions and functions can be returned as a value of other functions. An example of HOP in JavaScript would be something like the simple sort() method that you can apply to an array.

In its simplest form the sort() function takes an unordered/ordered array and sorts the array:

var a = [2,3,1,4]
document.write(a.sort())
// prints "1,2,3,4"

The sort() method however allows you to use a comparison function as an optional argument, allowing you to pass it a function as a parameter, ergo implementing HOP. Let's assume we've got an array of date objects that we want to sort in a chronological order:

array_of_dates.sort{ function (x, y) { return x.date - y.date; } }

Here we pass in an anonymous function as our comparison function to sort(). The anonymous function is called for each object in the array of dates and it must return a negative value when x < x ="="> y.

This technique is best used when you have at least two functions that perform the same take with a slight variance. Here you would then combine the functions by replacing the part(s) that are different with a function call to a separate function which is passed in to the more general function as a function parameter.

The Functional library implements string lambdas that allow you to express some of the functional programming tools more succinctly. The traditional JavaScript way of doing say a map or filter would be something like this:

map(function(x){return x+1}, [1,2,3]) // returns [2,3,4]
filter(function(x){return x>2}, [1,2,3,4]] // returns [3,4]
some(function(w){return w.length < 3}, 'are there any short words?'.split(' ')) // returns false

Instead, string lambdas allow you to write this in the following way:

map('x+1', [1,2,3])
select('x>2', [1,2,3,4])
some('_.length < 3', 'are there any short words?'.split(' '))

Here are some other way to bend a program to your functional will using simply map, reduce and filter:

// Double the items in a list:
map('*2', [1,2,3]) // [2, 4, 6]

// Find just the odd numbers:
filter('%2', [1,2,3,4]) // [1, 3]

// Find just the evens:
filter(not('%2'), [1,2,3,4]) // [2, 4]

// Find the length of the longest word:
reduce(Math.max, 0, map('_.length', 'how long is the longest word?'.split(' '))) // 7

// Parse a binary array:
reduce('2*x+y', 0, [1,0,1,0]) // 10

// Parse a (non-negative) decimal string:
reduce('x*10+y', 0, map('.charCodeAt(0)-48', '123'.split(/(?=.)/))) // 123
Much more succinct, clear to read and easier to understand.

Func Levels
Value-level programming manipulates values, transforming a sequence of inputs into an output. Function-level programming manipulates functions, applying operations to functions to construct a new function. This new function transforms the inputs into outputs.

How can we make JavaScript dance to a functional-level programming paradigm using the Functional library as meter? Here's some example's:

// Find the reciprocal only of values that test true:
map(guard('1/'), [1,2,null,4]) // [1, 0.5, null, 0.25]

// Apply '10+' only to even values, leaving the odd ones alone:
map(guard('10+', not('%2')), [1,2,3,4]) // [1, 12, 3, 14]

// Write a version of map that only applies to the evens:
var even = not('%2');
var mapEvens = map.prefilterAt(0, guard.rcurry(even));
mapEvens('10+', [1,2,3,4])

// Find the first power of two that's greater than 100:
until('>100', '2*')(1) // 128

// Or, the first three-digit power of two (these are equivalent):
until('String(_).length>2', '2*')(1)
until(compose('>2', pluck('length'), String), '2*')(1)
until(sequence(String, pluck('length'), '>2'), '2*')(1)
Hot/Medium/Mild Curry?
Partial function application (aka currying) transforms a function that takes n arguments into a function that takes only one argument and returns a curried function of n - 1 arguments.

In English please! OK, let's try:

Currying is the process of partially, or incrementally, supplying arguments to a function. Curried functions are delayed functions expecting the remainder of the arguments to be supplied. Once all the arguments are supplied, the function evaluates normally. So, curried functions lead to lazy execution of the complete function.

From the definitions above it is clear that partial function application, or specialisation, creates a new function out of an old one. To illustrate how we apply this with Functional we'll implement between(x, y, z) which determines whether y is bounded by x and z. We then curry the first and last arguments to produce a function that tests whether a number is positive:

// Function that needs to be curried
function increasing(a, b, c)
{
return a < b && b < c;
}

// Define the set of positive numbers via lazy evaluation
var positive = increasing.partial(0, _, Infinity);

// Determine if each of the values -1, 0 and 1 fall in our range
map(positive, [-1, 0, 1]) // [false, false, true]

// Define the set of negative numbers via lazy evaluation
var negative = increasing.partial(-Infinity, _, 0);

// Determine if each of -1, 0 and 1 fall in our range
map(negative, [-1, 0, 1]) // [true, false, false]
Currying leads to lazy evaluation which allows you to work with structures like the infinite sets we created above. Cool eh?!

Epilogue
Functional does a great job at making your life easier if you want to experiment with functional programming in JavaScript without getting yourself tangled up in the verbose, standard syntax. The creator does however offer a word of warning with regards to performance if you use this lib in production. Functional is also confirmed to work in Firefox 2.0, Safari 3.0, and MSIE 6.0.


Tuesday, August 14, 2007

Links

Dynamic Attribute-based Finder Extensions
szeryf has written a nice little exposé on how you can extend ActiveRecord::Base to add _or_ and _not_ operators to the dynamic finders that rails provides you with.

You can write the following types of finders out of the box with rails:

User.find_by_login_and_status(some_login, 1)
User.find_by_login_and_status_and_role_(some_login, 1, role)

The additional extensions as described in the article adds the following to the repertoire above:

User.find_by_login_and_status_or_role(some_login, 1, role)
User.find_by_login_and_status_not_role_(some_login, 1)

The two statements above would then result in the following SQL, respectively:

login = ? and (status = ? or (role = ?))
login = ? and (status = ? not (role = ?))

rparsec (the union of ActiveRecord :select and :include)
As you most probably already know you use :select in a find to modify the fields that are in your result set and :include to specify that related tables are loaded via joins to provide improved performance. Unfortunately you cannot use either of these two together due to the limitations imposed by the ActiveRecord implementation.

:select meets :include (or a pitch for rparsec) is an interesting article by Charlie Savage which suggests using a SQL SELECT parser to provide the required functionality.

He goes on to suggest doing this with the rparsec parser combinator framework.

The Controller Formula
Nick Kallen provides a lucid look at how one can produce poetic controller code.

Creating Multiple Models in One Action
This article is a followup on the previous one elaborating on the method that can be used to create multiple models from one action.

It covers the simplistic case where one model is simply created based on the creation of the other (when crating a group model, the creating uses needs to be the first member of the group) and the more complex case where there is a dependancy relationship between two models that needs to be enforced (a cyclops creation cannot succeed if the creation of the eye does not succeed).

Sunday, August 12, 2007

Prototype, IE and Edge Rails Failures

I recently wrote a little conceptual file upload application with scaffold_resource that used the iframe remoting pattern with some baked-in AJAX goodness to minimise the amount of data returned from the server as well as making the UI a lot more snappy.

Everything went well and tested a-OK in Firefox. Unfortunately my default development platform does not support IE so I only tested the app in IE a little later. To my horror IE rendered the page differently as well as spewing the following JS error:

Line: 1629
Char: 9
Error: Invalid target element for this operation.
Code: 0
URL: <REMOVED>

Prototype goodness wherefor art thou?
A few concise questions to the Oracle of Google and I found a thread started by Rob Sanheim which detailed the same problem I was seeing.

A fix, that worked for many of the thread readers, was proposed by Andy (12 December 2005 @ 1pm) in the same thread to deal with the way in which prototype inserts content in a tbody or tr tag.

So, off I went and upgraded my app to the latest Edge Rails using:

rake rails:freeze:edge

Edge Rails will you be the end of me?

Starting my app up I got a similar nasty to this:

/Applications/Locomotive2/Bundles/standardRailsFeb2007.locobundle/i386/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `gem_original_require': no such file to load -- active_resource (MissingSourceFile) from /Applications/Locomotive2/Bundles/standardRailsFeb2007.locobundle/i386/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:27:in `require' from /Users/joelmeyer/src/FotoDir/vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:495:in `require' from /Users/joelmeyer/src/FotoDir/vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:342:in `new_constants_in' from /Users/joelmeyer/src/FotoDir/vendor/rails/activerecord/lib/../../activesupport/lib/active_support/dependencies.rb:495:in `require' from ./config/../vendor/rails/railties/lib/initializer.rb:160:in `require_frameworks' from ./config/../vendor/rails/railties/lib/initializer.rb:160:in `each' from ./config/../vendor/rails/railties/lib/initializer.rb:160:in `require_frameworks' from ./config/../vendor/rails/railties/lib/initializer.rb:88:in `process' ... 8 levels... from /Applications/Locomotive2/Bundles/standardRailsFeb2007.locobundle/i386/lib/ruby/gems/1.8/gems/capistrano-1.4.1/lib/capistrano/cli.rb:12:in `execute!' from /Applications/Locomotive2/Bundles/standardRailsFeb2007.locobundle/i386/lib/ruby/gems/1.8/gems/capistrano-1.4.1/bin/cap:11 from /Applications/Locomotive2/Bundles/standardRailsFeb2007.locobundle/i386/bin/cap:16:in `load' from /Applications/Locomotive2/Bundles/standardRailsFeb2007.locobundle/i386/bin/cap:16

Seems that when you're using Edge Rails you need to use the active resource gem in tandem or you world will turn pear-shaped. Installing the gem, with dependancies did the trick:

gem install -y activeresource --source http://gems.rubyonrails.org

IE: Dark side of the moon
So, I have now upgraded to the latest prototype lib (via the Edge Rails upgrade) and got Edge Rails to run with the active_scaffold and active resources I was using in my app.

Was everything fine then and did I get to live a more fulfilling existence? NAY!

Back to the entry by Rob Sanheim and I noticed that Chris Nolan reported that the prototype lib had been fixed but that he was still experiencing the same issue.

There is a boat and I feel that Chris and I are both in it together, brothers in misery.

While debugging the issue with trusty old JS alert() he found that he was trying to insert content at an id that belonged to a table tag which was not supported. The tags supported for this were of course tbody and/or tr.

Even though the tbody tag seems to be optional according to the W3C IE still does not allow you to insert the content based on a table id.

The simple addition of the required tbody tags cured all.

Sunday, August 5, 2007

Turning responsibility inside-out via delegation

5 August 2007

Turning responsibility inside-out via delegation

What is the delegation pattern? You find this where you have an object that expresses a certain behaviour externally but internally defers, or, delegates the responsibility for implementation to another object in an inversion of responsibility.

Turning responsibility inside-out
Ruby provides five ways to accomplish this: three (SimpleDelegator, DelegateClass and Delegator) encapsulated in the delegate library and the remaining two (Forwardable and SingleForwardable) via the forwardable library.

Let's use a queue data structure that delegates to an array to illustrate the various ways of accomplishing delegation.

SimpleDelegator
This is the simplest way to accomplish delegation. You simply pass an object to the constructor and all methods supported by the object will be delegated.

_This object can be changed later._

require 'delegate'

class Queue
def initialize
@sd = SimpleDelegator.new([]) # we delegate to an array object
end

def enqueue(element)
@sd.push(element)
end

def dequeue
@sd.shift
end
end

q = Queue.new
q.enqueue(10) # [10]
q.enqueue(20) # [10, 20]
q.dequeue # [20]

If you want to change the object you're delegating to you just use __setobj__(obj). You should just keep in mind that this does *not* cause SimpleDelegator’s methods to change which means that you should only be delegating to objects of the same type as the original delegate to avoid nastiness.

DelegateClass
If SimpleDelegator does not spin your propeller then the next step would be to look at DelegateClass. Using the top level DelegateClass method to setup delegation through class inheritance is considered more flexible and is seemingly the most common use for this library.

require 'delegate'

class Queue < DelegateClass(Array) # we delegate to an array object
def initialize(arg=[])
super(arg)
end

alias_method :enqueue, :push # alias_method sets up the method aliasing for us
alias_method :dequeue, :shift
end

q = Queue.new
q.enqueue(10) # [10]
q.enqueue(20) # [10, 20]
q.dequeue # [20]

Delegator
The final tool from the delegator library is Delegator which provides you with full control over the delegation scheme. The contrived example below is derived from the SimpleDelegator’s implementation.

require 'delegate'

class QueueDelegator < Delegator # inherit from the Delegator class
def initialize(obj)
super # pass obj to Delegator constructor
@_sd_obj = obj # store obj for future use
end

def __getobj__
@_sd_obj # return the object we are delegating to
end

def __setobj__(obj)
@_sd_obj = obj # change delegation object, a feature we're providing
end
end

The conventional wisdom here however is that you should most likely be using the forwardable library instead of Delegator.

Fowardable
If you need class-level delegation this is your beast of burden.

require 'forwardable'

class Queue
extend Forwardable

def initialize(obj=[])
@queue = obj # delegate to this object
end

def_delegator :@queue, :push, :enqueue
def_delegator :@queue, :shift, :dequeue
def_delegators :@queue, :clear, :empty?, :length, :size, :<<
end

There are a few things to take note of here. First, def_delegator is used to set up the delegation relationship between the method call, the delegated object and the method to call on the delegated object.

Second, notice the syntax (:@queue, instead of @queue or :queue) to specify the delegated object we're defining methods for. This is simply an artefact of the way that Forwardable is implemented.

SingleForwardable
Where Forwardable provides class-level delegation, SingleForwardable provides object level delegation. For this example I'll simply copy the example provided in the library documentation.

require 'forwardable'

printer = String.new
printer.extend SingleForwardable # prepare object for delegation
printer.def_delegator "STDOUT", "puts" # add delegation for STDOUT.puts()
printer.puts "Howdy!"

Epilogue
Using DelegateClass and Forwardable for your delegation needs will most likely cover most of the cases you may end up needing to implement the delegator pattern.

Did we default or not?

You may sometimes find yourself having to distinguish whether a method attribute was supplied externally or taken from the default specified in the method definition.

Let's say, for example, that you want to warn a user when they have neglected to set an attribute but still continue with execution. Here is a snippet that would accomplish this:

irb(main):060:0> def some_method(first, second=(flag=true; '2nd'))
irb(main):061:1> p "Default value #{second} used for unspecified parameter 'second'" if flag.inspect == "true"
irb(main):062:1> end
=> nil
irb(main):063:0> some_method(1,2)
=> nil
irb(main):064:0> some_method(1,'2nd')
=> nil
irb(main):065:0> some_method(1)
"Default value 2nd used for unspecified parameter 'second'"
=> nil
irb(main):066:0>
Can you work out what is going on in the method parameter declaration?

All that's happening is that the code in the round brackets after the equals sign defines a local variable _flag_, sets its value and returns the default value we want to set it to.

Ruby rocks!

Sunday, July 29, 2007

Tracking fast-paced packages on debian based systems (aka debian-volatile project)

debian-volatile
If you run some ISP services (your own mail server with virus and/or spam scanning tools) you will have run into the age old problem that the scanning tools in the stable distribution do not evolve as fast as they should to keep up with their fast-paced projects.

Even continual updates of the software in your distribution are not enough to stay up to date as the release cycle of the stable distribution is out of sync with the speed at which things change in the wild.

According to the debian-volatile project page:

The main goal of volatile is allowing system administrators to update their systems
in a nice, consistent way, without getting the drawbacks of using unstable, even
without getting the drawbacks for the selected packages. So debian-volatile will
only contain changes to stable programs that are necessary to keep them functional.

volatile-sloppy
Great effort goes into ensuring that no functional changes are made to packages in debian-volatile (so that configuration file changes, etc. are not required) for painless upgrades. Unfortunately painful upgrades are not always avoidable so a volatile-sloppy section was created to contain packages that are fast-paced but also require some functional change to how it runs, is installed or configured.

Security
You should note that the debian-volatile project is not supported by the _official_ security team. This responsibility falls to the debian-volatile team who currently has at least one member that is shared with the official debian testing security team.

How do I use it?
Add the relevant repository (volatile and/or volatile-sloppy) to your /etc/apt/sources.list file:

Sarge
deb http://volatile.debian.org/debian-volatile sarge/volatile main contrib non-free
deb http://volatile.debian.org/debian-volatile sarge/volatile-sloppy main contrib non-free

Etch
deb http://volatile.debian.org/debian-volatile etch/volatile main contrib non-free
deb http://volatile.debian.org/debian-volatile etch/volatile-sloppy main contrib non-free


Save sources.list and run _atp-get update_ which should generate something like this (your listing will vary depending on the repositories you have listed in your sources file):

# apt-get update
Get:1 http://archive.ubuntu.com dapper Release.gpg [189B]
Get:2 http://us.archive.ubuntu.com dapper Release.gpg [189B]
Get:3 http://us.archive.ubuntu.com dapper-backports Release.gpg [191B]
Get:4 http://archive.ubuntu.com dapper-updates Release.gpg [191B]
Get:5 http://volatile.debian.org etch/volatile Release.gpg [189B]
Hit http://us.archive.ubuntu.com dapper Release
Hit http://archive.ubuntu.com dapper Release
Get:6 http://volatile.debian.org etch/volatile Release [40.7kB]
Hit http://archive.ubuntu.com dapper-updates Release
Hit http://us.archive.ubuntu.com dapper-backports Release
Hit http://archive.ubuntu.com dapper/main Packages
Hit http://archive.ubuntu.com dapper/restricted Packages
Hit http://us.archive.ubuntu.com dapper/universe Packages
Hit http://us.archive.ubuntu.com dapper/universe Sources
Hit http://archive.ubuntu.com dapper/main Sources
Hit http://archive.ubuntu.com dapper/restricted Sources
Hit http://archive.ubuntu.com dapper-updates/main Packages
Hit http://archive.ubuntu.com dapper-updates/restricted Packages
Hit http://us.archive.ubuntu.com dapper-backports/main Packages
Hit http://us.archive.ubuntu.com dapper-backports/restricted Packages
Hit http://us.archive.ubuntu.com dapper-backports/universe Packages
Hit http://archive.ubuntu.com dapper-updates/main Sources
Hit http://archive.ubuntu.com dapper-updates/restricted Sources
Hit http://us.archive.ubuntu.com dapper-backports/multiverse Packages
Hit http://us.archive.ubuntu.com dapper-backports/main Sources
Hit http://us.archive.ubuntu.com dapper-backports/restricted Sources
Hit http://us.archive.ubuntu.com dapper-backports/universe Sources
Hit http://us.archive.ubuntu.com dapper-backports/multiverse Sources
Ign http://volatile.debian.org etch/volatile Release
Get:7 http://volatile.debian.org etch/volatile/main Packages [3953B]
Hit http://volatile.debian.org etch/volatile/contrib Packages
Hit http://volatile.debian.org etch/volatile/non-free Packages
Get:8 http://security.ubuntu.com dapper-security Release.gpg [191B]
Hit http://security.ubuntu.com dapper-security Release
Hit http://security.ubuntu.com dapper-security/main Packages
Hit http://security.ubuntu.com dapper-security/restricted Packages
Hit http://security.ubuntu.com dapper-security/main Sources
Hit http://security.ubuntu.com dapper-security/restricted Sources
Hit http://security.ubuntu.com dapper-security/universe Packages
Hit http://security.ubuntu.com dapper-security/universe Sources
Fetched 44.8kB in 5s (7554B/s)
Reading package lists... Done
W: GPG error: http://volatile.debian.org etch/volatile Release: The following signatures couldn't be verified because the public key is not available: NO_PUBKEY EC61E0B0BBE55AB3
W: You may want to run apt-get update to correct these problems
#

The inclusion of the debian-volatile release fails because we do not have a key to authenticate the repository. Adding the following will import their key (mentioned as EC61E0B0BBE55AB3 above) into your key ring:

# gpg --keyserver subkeys.pgp.net --recv-keys EC61E0B0BBE55AB3
gpg: directory `/root/.gnupg' created
gpg: new configuration file `/root/.gnupg/gpg.conf' created
gpg: WARNING: options in `/root/.gnupg/gpg.conf' are not yet active during this run
gpg: keyring `/root/.gnupg/secring.gpg' created
gpg: keyring `/root/.gnupg/pubring.gpg' created
gpg: requesting key BBE55AB3 from hkp server subkeys.pgp.net
gpg: /root/.gnupg/trustdb.gpg: trustdb created
gpg: key BBE55AB3: public key "Debian-Volatile Archive Automatic Signing Key (4.0/etch)" imported
gpg: no ultimately trusted keys found
gpg: Total number processed: 1
gpg: imported: 1
# gpg --armor --export EC61E0B0BBE55AB3 | apt-key add -
gpg: no ultimately trusted keys found
OK
#

Another spin of _apt-get update_ (and possibly _apt-get upgrade_ if their are any outdated packages) should then do the trick.

Tuesday, July 24, 2007

Links

IRB
Dr Nic has a great little article describing his favourite additions to his .irbrc. He covers some common productivity wins such as:
  • TABed auto-completion
  • Map by method which allows you to get rid of constructs like articles.columns.map {|p| p.name} or articles.columns.map &:name and simply replace it with a plural: articles.columns.names or articles.columns.name
  • MethodFinder/Object.what?
  • pp
  • Auto-tabbing
GuessMethod
This little gem is the best bad idea ever! Gone are those frustrating typos that waste extra cycles finding and fixing them.

Wirble
Continuing on the irb enhancements theme do yourself a favour and have a look at Wirble. It offers you tab-completion, history, and a built-in ri command as well as colorised results and a couple other goodies.

About Me

My photo
I love solving real-world problems with code and systems (web apps, distributed systems and all the bits and pieces in-between).