+
+class OrderedHash < Hash
+ alias_method :store, :[]=
+ alias_method :each_pair, :each
+ attr_reader :keys
+
+ def initialize *a
+ @keys = []
+ a.each { |k, v| self[k] = v }
+ end
+
+ def []= key, val
+ @keys << key unless member?(key)
+ super
+ end
+
+ def values; keys.map { |k| self[k] } end
+ def index key; @keys.index key end
+
+ def delete key
+ @keys.delete key
+ super
+ end
+
+ def each; @keys.each { |k| yield k, self[k] } end
+end
+
+## easy thread-safe class for determining who's the "winner" in a race (i.e.
+## first person to hit the finish line
+class FinishLine
+ def initialize
+ @m = Mutex.new
+ @over = false
+ end
+
+ def winner?
+ @m.synchronize { !@over && @over = true }
+ end
+end
+
+class Iconv
+ def self.easy_decode target, charset, text
+ return text if charset =~ /^(x-unknown|unknown[-_]?8bit|ascii[-_]?7[-_]?bit)$/i
+ charset = case charset
+ when /UTF[-_]?8/i: "utf-8"
+ when /(iso[-_])?latin[-_]?1$/i: "ISO-8859-1"
+ when /unicode[-_]1[-_]1[-_]utf[-_]7/i: "utf-7"
+ else charset
+ end
+
+ # Convert:
+ #
+ # Remember - Iconv.open(to, from)!
+ Iconv.iconv(target + "//IGNORE", charset, text + " ").join[0 .. -2]
+ end
+end