diff --git a/vendor/gems/hpricot-0.6/CHANGELOG b/vendor/gems/hpricot-0.6/CHANGELOG
new file mode 100644
index 0000000..2c7051b
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/CHANGELOG
@@ -0,0 +1,62 @@
+= 0.6
+=== 15th June, 2007
+* Hpricot for JRuby -- nice work Ola Bini!
+* Inline Markaby for Hpricot documents.
+* XML tags and attributes are no longer downcased like HTML is.
+* new syntax for grabbing everything between two elements using a Range in the search method: (doc/("font".."font/br")) or in nodes_at like so: (doc/"font").nodes_at("*".."br"). Only works with either a pair of siblings or a set of a parent and a sibling.
+* Ignore self-closing endings on tags (such as form) which are containers. Treat them like open parent tags. Reported by Jonathan Nichols on the hpricot list.
+* Escaping of attributes, yanked from Jim Weirich and Sam Ruby's work in Builder.
+* Element#raw_attributes gives unescaped data. Element#attributes gives escaped.
+* Added: Elements#attr, Elements#remove_attr, Elements#remove_class.
+* Added: Traverse#preceding, Traverse#following, Traverse#previous, Traverse#next.
+
+= 0.5
+=== 31rd January, 2007
+
+* support for a[text()="Click Me!"] and h3[text()*="space"] and the like.
+* Hpricot.buffer_size accessor for increasing Hpricot's buffer if you're encountering huge ASP.NET viewstate attribs.
+* some support for colons in tag names (not full namespace support yet.)
+* Element.to_original_html will attempt to preserve the original HTML while merging your changes.
+* Element.to_plain_text converts an element's contents to a simple text format.
+* Element.inner_text removes all tags and returns text nodes concatenated into a single string.
+* no @raw_string variable kept for comments, text, and cdata -- as it's redundant.
+* xpath-style indices (//p/a[1]) but keep in mind that they aren't zero-based.
+* node_position is the index among all sibling nodes, while position is the position among children of identical type.
+* comment() and text() search criteria, like: //p/text(), which selects all text inside paragraph tags.
+* every element has css_path and xpath methods which return respective absolute paths.
+* more flexibility all around: in parsing attributes, tags, comments and cdata.
+
+= 0.4
+=== 11th August, 2006
+
+* The :fixup_tags option will try to sort out the hierarchy so elements end up with the right parents.
+* Elements such as *script* and *style* (identified as having CDATA contents) receive a single text node as their children now. Previously, Hpricot was parsing out tags found in scripts.
+* Better scanning of partially quoted attributes (found by Brent Beardsly on http://uswebgen.com/)
+* Better scanning of unquoted attributes -- thanks to Aaron Patterson for the test cases!
+* Some tags were being output in the empty tag style, although browsers hated that. FIXED!
+* Added Elements#at for finding single elements.
+* Added Elem::Trav#[] and Elem::Trav#[]= for reading and writing attributes.
+
+= 0.3
+=== 7th July, 2006
+
+* Fixed negative string size error on empty tokens. (news.bbc.co.uk)
+* Allow the parser to accept just text nodes. (such as: Hpricot.parse('TEXT'))
+* from JQuery to Hpricot::Elements: remove, empty, append, prepend, before, after, wrap, set,
+ html(...), to_html, to_s.
+* on containers: to_html, replace_child, insert_before, insert_after, innerHTML=.
+* Hpricot(...) is an alias for parse.
+* open up all properties to setters, let people do as they may.
+* use to_html for the full html of a node or set of elements.
+* doctypes were messed.
+
+= 0.2
+=== 4th July, 2006
+
+* Rewrote the HTree parser to be simpler, more adequate for the common man. Will add encoding back in later.
+
+= 0.1
+=== 3rd July, 2006
+
+* For whatever reason, wrote this HTML parser in C.
+ I guess Ragel is addictive and I want to improve HTree.
diff --git a/vendor/gems/hpricot-0.6/COPYING b/vendor/gems/hpricot-0.6/COPYING
new file mode 100644
index 0000000..94b6b84
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/COPYING
@@ -0,0 +1,18 @@
+Copyright (c) 2006 why the lucky stiff
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to
+deal in the Software without restriction, including without limitation the
+rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+sell copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/gems/hpricot-0.6/README b/vendor/gems/hpricot-0.6/README
new file mode 100644
index 0000000..6443214
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/README
@@ -0,0 +1,284 @@
+= Hpricot, Read Any HTML
+
+Hpricot is a fast, flexible HTML parser written in C. It's designed to be very
+accommodating (like Tanaka Akira's HTree) and to have a very helpful library
+(like some JavaScript libs -- JQuery, Prototype -- give you.) The XPath and CSS
+parser, in fact, is based on John Resig's JQuery.
+
+Also, Hpricot can be handy for reading broken XML files, since many of the same
+techniques can be used. If a quote is missing, Hpricot tries to figure it out.
+If tags overlap, Hpricot works on sorting them out. You know, that sort of
+thing.
+
+*Please read this entire document* before making assumptions about how this
+software works.
+
+== An Overview
+
+Let's clear up what Hpricot is.
+
+# Hpricot is *a standalone library*. It requires no other libraries. Just Ruby!
+# While priding itself on speed, Hpricot *works hard to sort out bad HTML* and
+ pays a small penalty in order to get that right. So that's slightly more important
+ to me than speed.
+# *If you can see it in Firefox, then Hpricot should parse it.* That's
+ how it should be! Let me know the minute it's otherwise.
+# Primarily, Hpricot is used for reading HTML and tries to sort out troubled
+ HTML by having some idea of what good HTML is. Some people still like to use
+ Hpricot for XML reading, but *remember to use the Hpricot::XML() method* for that!
+
+== The Hpricot Kingdom
+
+First, here are all the links you need to know:
+
+* http://code.whytheluckystiff.net/hpricot is the Hpricot wiki and bug tracker.
+ Go there for news and recipes and patches. It's the center of activity.
+* http://code.whytheluckystiff.net/svn/hpricot/trunk is the main Subversion
+ repository for Hpricot. You can get the latest code there.
+* http://code.whytheluckystiff.net/doc/hpricot is the home for the latest copy of
+ this reference.
+* See COPYING for the terms of this software. (Spoiler: it's absolutely free.)
+
+If you have any trouble, don't hesitate to contact the author. As always, I'm
+not going to say "Use at your own risk" because I don't want this library to be
+risky. If you trip on something, I'll share the liability by repairing things
+as quickly as I can. Your responsibility is to report the inadequacies.
+
+== Installing Hpricot
+
+You may get the latest stable version from Rubyforge. Win32 binaries and source
+gems are available.
+
+ $ gem install hpricot
+
+As Hpricot is still under active development, you can also try the most recent
+candidate build here:
+
+ $ gem install hpricot --source http://code.whytheluckystiff.net
+
+The development gem is usually in pretty good shape actually. You can also
+get the bleeding edge code or plain Ruby tarballs on the wiki.
+
+== An Hpricot Showcase
+
+We're going to run through a big pile of examples to get you jump-started.
+Many of these examples are also found at
+http://code.whytheluckystiff.net/hpricot/wiki/HpricotBasics, in case you
+want to add some of your own.
+
+=== Loading Hpricot Itself
+
+You have probably got the gem, right? To load Hpricot:
+
+ require 'rubygems'
+ require 'hpricot'
+
+If you've installed the plain source distribution, go ahead and just:
+
+ require 'hpricot'
+
+=== Load an HTML Page
+
+The Hpricot() method takes a string or any IO object and loads the
+contents into a document object.
+
+ doc = Hpricot("
A simple test string.
")
+
+To load from a file, just get the stream open:
+
+ doc = open("index.html") { |f| Hpricot(f) }
+
+To load from a web URL, use open-uri, which comes with Ruby:
+
+ require 'open-uri'
+ doc = open("http://qwantz.com/") { |f| Hpricot(f) }
+
+Hpricot uses an internal buffer to parse the file, so the IO will stream
+properly and large documents won't be loaded into memory all at once. However,
+the parsed document object will be present in memory, in its entirety.
+
+=== Search for Elements
+
+Use Doc.search:
+
+ doc.search("//p[@class='posted']")
+ #=> #
+
+Doc.search can take an XPath or CSS expression. In the above example,
+all paragraph
elements are grabbed which have a class
+attribute of "posted".
+
+A shortcut is to use the divisor:
+
+ (doc/"p.posted")
+ #=> #
+
+=== Finding Just One Element
+
+If you're looking for a single element, the at method will return the
+first element matched by the expression. In this case, you'll get back the
+element itself rather than the Hpricot::Elements array.
+
+ doc.at("body")['onload']
+
+The above code will find the body tag and give you back the onload
+attribute. This is the most common reason to use the element directly: when
+reading and writing HTML attributes.
+
+=== Fetching the Contents of an Element
+
+Just as with browser scripting, the inner_html property can be used to
+get the inner contents of an element.
+
+ (doc/"#elementID").inner_html
+ #=> "..contents.."
+
+If your expression matches more than one element, you'll get back the contents
+of ''all the matched elements''. So you may want to use first to be
+sure you get back only one.
+
+ (doc/"#elementID").first.inner_html
+ #=> "..contents.."
+
+=== Fetching the HTML for an Element
+
+If you want the HTML for the whole element (not just the contents), use
+to_html:
+
+ (doc/"#elementID").to_html
+ #=> "
"
+ #
+ def empty
+ each { |x| x.inner_html = nil }
+ end
+
+ # Add to the end of the contents inside each element in this list.
+ # Pass in an HTML +str+, which is turned into Hpricot elements.
+ def append(str = nil, &blk)
+ each { |x| x.html(x.children + Hpricot.make(str, &blk)) }
+ end
+
+ # Add to the start of the contents inside each element in this list.
+ # Pass in an HTML +str+, which is turned into Hpricot elements.
+ def prepend(str = nil, &blk)
+ each { |x| x.html(Hpricot.make(str, &blk) + x.children) }
+ end
+
+ # Add some HTML just previous to each element in this list.
+ # Pass in an HTML +str+, which is turned into Hpricot elements.
+ def before(str = nil, &blk)
+ each { |x| x.parent.insert_before Hpricot.make(str, &blk), x }
+ end
+
+ # Just after each element in this list, add some HTML.
+ # Pass in an HTML +str+, which is turned into Hpricot elements.
+ def after(str = nil, &blk)
+ each { |x| x.parent.insert_after Hpricot.make(str, &blk), x }
+ end
+
+ # Wraps each element in the list inside the element created by HTML +str+.
+ # If more than one element is found in the string, Hpricot locates the
+ # deepest spot inside the first element.
+ #
+ # doc.search("a[@href]").
+ # wrap(%{
})
+ #
+ # This code wraps every link on the page inside a +div.link+ and a +div.link_inner+ nest.
+ def wrap(str = nil, &blk)
+ each do |x|
+ wrap = Hpricot.make(str, &blk)
+ nest = wrap.detect { |w| w.respond_to? :children }
+ unless nest
+ raise Exception, "No wrapping element found."
+ end
+ x.parent.replace_child(x, wrap)
+ nest = nest.children.first until nest.empty?
+ nest.html(nest.children + [x])
+ end
+ end
+
+ # Gets and sets attributes on all matched elements.
+ #
+ # Pass in a +key+ on its own and this method will return the string value
+ # assigned to that attribute for the first elements. Or +nil+ if the
+ # attribute isn't found.
+ #
+ # doc.search("a").attr("href")
+ # #=> "http://hacketyhack.net/"
+ #
+ # Or, pass in a +key+ and +value+. This will set an attribute for all
+ # matched elements.
+ #
+ # doc.search("p").attr("class", "basic")
+ #
+ # You may also use a Hash to set a series of attributes:
+ #
+ # (doc/"a").attr(:class => "basic", :href => "http://hackety.org/")
+ #
+ # Lastly, a block can be used to rewrite an attribute based on the element
+ # it belongs to. The block will pass in an element. Return from the block
+ # the new value of the attribute.
+ #
+ # records.attr("href") { |e| e['href'] + "#top" }
+ #
+ # This example adds a #top anchor to each link.
+ #
+ def attr key, value = nil, &blk
+ if value or blk
+ each do |el|
+ el.set_attribute(key, value || blk[el])
+ end
+ return self
+ end
+ if key.is_a? Hash
+ key.each { |k,v| self.attr(k,v) }
+ return self
+ else
+ return self[0].get_attribute(key)
+ end
+ end
+ alias_method :set, :attr
+
+ # Adds the class to all matched elements.
+ #
+ # (doc/"p").add_class("bacon")
+ #
+ # Now all paragraphs will have class="bacon".
+ def add_class class_name
+ each do |el|
+ next unless el.respond_to? :get_attribute
+ classes = el.get_attribute('class').to_s.split(" ")
+ el.set_attribute('class', classes.push(class_name).uniq.join(" "))
+ end
+ self
+ end
+
+ # Remove an attribute from each of the matched elements.
+ #
+ # (doc/"input").remove_attr("disabled")
+ #
+ def remove_attr name
+ each do |el|
+ next unless el.respond_to? :remove_attribute
+ el.remove_attribute(name)
+ end
+ self
+ end
+
+ # Removes a class from all matched elements.
+ #
+ # (doc/"span").remove_class("lightgrey")
+ #
+ # Or, to remove all classes:
+ #
+ # (doc/"span").remove_class
+ #
+ def remove_class name = nil
+ each do |el|
+ next unless el.respond_to? :get_attribute
+ if name
+ classes = el.get_attribute('class').to_s.split(" ")
+ el.set_attribute('class', (classes - [name]).uniq.join(" "))
+ else
+ el.remove_attribute("class")
+ end
+ end
+ self
+ end
+
+ ATTR_RE = %r!\[ *(?:(@)([\w\(\)-]+)|([\w\(\)-]+\(\))) *([~\!\|\*$\^=]*) *'?"?([^\]'"]*)'?"? *\]!i
+ BRACK_RE = %r!(\[) *([^\]]*) *\]+!i
+ FUNC_RE = %r!(:)?([a-zA-Z0-9\*_-]*)\( *[\"']?([^ \)]*?)['\"]? *\)!
+ CUST_RE = %r!(:)([a-zA-Z0-9\*_-]*)()!
+ CATCH_RE = %r!([:\.#]*)([a-zA-Z0-9\*_-]+)!
+
+ def self.filter(nodes, expr, truth = true)
+ until expr.empty?
+ _, *m = *expr.match(/^(?:#{ATTR_RE}|#{BRACK_RE}|#{FUNC_RE}|#{CUST_RE}|#{CATCH_RE})/)
+ break unless _
+
+ expr = $'
+ m.compact!
+ if m[0] == '@'
+ m[0] = "@#{m.slice!(2,1)}"
+ end
+
+ if m[0] == '[' && m[1] =~ /^\d+$/
+ m = [":", "nth", m[1].to_i-1]
+ end
+
+ if m[0] == ":" && m[1] == "not"
+ nodes, = Elements.filter(nodes, m[2], false)
+ elsif "#{m[0]}#{m[1]}" =~ /^(:even|:odd)$/
+ new_nodes = []
+ nodes.each_with_index {|n,i| new_nodes.push(n) if (i % 2 == (m[1] == "even" ? 0 : 1)) }
+ nodes = new_nodes
+ elsif "#{m[0]}#{m[1]}" =~ /^(:first|:last)$/
+ nodes = [nodes.send(m[1])]
+ else
+ meth = "filter[#{m[0]}#{m[1]}]" unless m[0].empty?
+ if meth and Traverse.method_defined? meth
+ args = m[2..-1]
+ else
+ meth = "filter[#{m[0]}]"
+ if Traverse.method_defined? meth
+ args = m[1..-1]
+ end
+ end
+ i = -1
+ nodes = Elements[*nodes.find_all do |x|
+ i += 1
+ x.send(meth, *([*args] + [i])) ? truth : !truth
+ end]
+ end
+ end
+ [nodes, expr]
+ end
+
+ # Given two elements, attempt to gather an Elements array of everything between
+ # (and including) those two elements.
+ def self.expand(ele1, ele2, excl=false)
+ ary = []
+ offset = excl ? -1 : 0
+
+ if ele1 and ele2
+ # let's quickly take care of siblings
+ if ele1.parent == ele2.parent
+ ary = ele1.parent.children[ele1.node_position..(ele2.node_position+offset)]
+ else
+ # find common parent
+ p, ele1_p = ele1, [ele1]
+ ele1_p.unshift p while p.respond_to?(:parent) and p = p.parent
+ p, ele2_p = ele2, [ele2]
+ ele2_p.unshift p while p.respond_to?(:parent) and p = p.parent
+ common_parent = ele1_p.zip(ele2_p).select { |p1, p2| p1 == p2 }.flatten.last
+
+ child = nil
+ if ele1 == common_parent
+ child = ele2
+ elsif ele2 == common_parent
+ child = ele1
+ end
+
+ if child
+ ary = common_parent.children[0..(child.node_position+offset)]
+ end
+ end
+ end
+
+ return Elements[*ary]
+ end
+
+ def filter(expr)
+ nodes, = Elements.filter(self, expr)
+ nodes
+ end
+
+ def not(expr)
+ if expr.is_a? Traverse
+ nodes = self - [expr]
+ else
+ nodes, = Elements.filter(self, expr, false)
+ end
+ nodes
+ end
+
+ private
+ def copy_node(node, l)
+ l.instance_variables.each do |iv|
+ node.instance_variable_set(iv, l.instance_variable_get(iv))
+ end
+ end
+
+ end
+
+ module Traverse
+ def self.filter(tok, &blk)
+ define_method("filter[#{tok.is_a?(String) ? tok : tok.inspect}]", &blk)
+ end
+
+ filter '' do |name,i|
+ name == '*' || (self.respond_to?(:name) && self.name.downcase == name.downcase)
+ end
+
+ filter '#' do |id,i|
+ self.elem? and get_attribute('id').to_s == id
+ end
+
+ filter '.' do |name,i|
+ self.elem? and classes.include? name
+ end
+
+ filter :lt do |num,i|
+ self.position < num.to_i
+ end
+
+ filter :gt do |num,i|
+ self.position > num.to_i
+ end
+
+ nth = proc { |num,i| self.position == num.to_i }
+ nth_first = proc { |*a| self.position == 0 }
+ nth_last = proc { |*a| self == parent.children_of_type(self.name).last }
+
+ filter :nth, &nth
+ filter :eq, &nth
+ filter ":nth-of-type", &nth
+
+ filter :first, &nth_first
+ filter ":first-of-type", &nth_first
+
+ filter :last, &nth_last
+ filter ":last-of-type", &nth_last
+
+ filter :even do |num,i|
+ self.position % 2 == 0
+ end
+
+ filter :odd do |num,i|
+ self.position % 2 == 1
+ end
+
+ filter ':first-child' do |i|
+ self == parent.containers.first
+ end
+
+ filter ':nth-child' do |arg,i|
+ case arg
+ when 'even'; (parent.containers.index(self) + 1) % 2 == 0
+ when 'odd'; (parent.containers.index(self) + 1) % 2 == 1
+ else self == (parent.containers[arg.to_i + 1])
+ end
+ end
+
+ filter ":last-child" do |i|
+ self == parent.containers.last
+ end
+
+ filter ":nth-last-child" do |arg,i|
+ self == parent.containers[-1-arg.to_i]
+ end
+
+ filter ":nth-last-of-type" do |arg,i|
+ self == parent.children_of_type(self.name)[-1-arg.to_i]
+ end
+
+ filter ":only-of-type" do |arg,i|
+ parent.children_of_type(self.name).length == 1
+ end
+
+ filter ":only-child" do |arg,i|
+ parent.containers.length == 1
+ end
+
+ filter :parent do
+ containers.length > 0
+ end
+
+ filter :empty do
+ containers.length == 0
+ end
+
+ filter :root do
+ self.is_a? Hpricot::Doc
+ end
+
+ filter 'text' do
+ self.text?
+ end
+
+ filter 'comment' do
+ self.comment?
+ end
+
+ filter :contains do |arg, ignore|
+ html.include? arg
+ end
+
+
+
+ pred_procs =
+ {'text()' => proc { |ele, *_| ele.inner_text.strip },
+ '@' => proc { |ele, attr, *_| ele.get_attribute(attr).to_s if ele.elem? }}
+
+ oper_procs =
+ {'=' => proc { |a,b| a == b },
+ '!=' => proc { |a,b| a != b },
+ '~=' => proc { |a,b| a.split(/\s+/).include?(b) },
+ '|=' => proc { |a,b| a =~ /^#{Regexp::quote b}(-|$)/ },
+ '^=' => proc { |a,b| a.index(b) == 0 },
+ '$=' => proc { |a,b| a =~ /#{Regexp::quote b}$/ },
+ '*=' => proc { |a,b| idx = a.index(b) }}
+
+ pred_procs.each do |pred_n, pred_f|
+ oper_procs.each do |oper_n, oper_f|
+ filter "#{pred_n}#{oper_n}" do |*a|
+ qual = pred_f[self, *a]
+ oper_f[qual, a[-2]] if qual
+ end
+ end
+ end
+
+ filter 'text()' do |val,i|
+ !self.inner_text.strip.empty?
+ end
+
+ filter '@' do |attr,val,i|
+ self.elem? and has_attribute? attr
+ end
+
+ filter '[' do |val,i|
+ self.elem? and search(val).length > 0
+ end
+
+ end
+end
diff --git a/vendor/gems/hpricot-0.6/lib/hpricot/htmlinfo.rb b/vendor/gems/hpricot-0.6/lib/hpricot/htmlinfo.rb
new file mode 100644
index 0000000..951ce17
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/lib/hpricot/htmlinfo.rb
@@ -0,0 +1,672 @@
+module Hpricot
+# The code below is auto-generated. Don't edit manually.
+ # :stopdoc:
+ NamedCharacters =
+{"AElig"=>198, "Aacute"=>193, "Acirc"=>194, "Agrave"=>192, "Alpha"=>913,
+ "Aring"=>197, "Atilde"=>195, "Auml"=>196, "Beta"=>914, "Ccedil"=>199,
+ "Chi"=>935, "Dagger"=>8225, "Delta"=>916, "ETH"=>208, "Eacute"=>201,
+ "Ecirc"=>202, "Egrave"=>200, "Epsilon"=>917, "Eta"=>919, "Euml"=>203,
+ "Gamma"=>915, "Iacute"=>205, "Icirc"=>206, "Igrave"=>204, "Iota"=>921,
+ "Iuml"=>207, "Kappa"=>922, "Lambda"=>923, "Mu"=>924, "Ntilde"=>209, "Nu"=>925,
+ "OElig"=>338, "Oacute"=>211, "Ocirc"=>212, "Ograve"=>210, "Omega"=>937,
+ "Omicron"=>927, "Oslash"=>216, "Otilde"=>213, "Ouml"=>214, "Phi"=>934,
+ "Pi"=>928, "Prime"=>8243, "Psi"=>936, "Rho"=>929, "Scaron"=>352, "Sigma"=>931,
+ "THORN"=>222, "Tau"=>932, "Theta"=>920, "Uacute"=>218, "Ucirc"=>219,
+ "Ugrave"=>217, "Upsilon"=>933, "Uuml"=>220, "Xi"=>926, "Yacute"=>221,
+ "Yuml"=>376, "Zeta"=>918, "aacute"=>225, "acirc"=>226, "acute"=>180,
+ "aelig"=>230, "agrave"=>224, "alefsym"=>8501, "alpha"=>945, "amp"=>38,
+ "and"=>8743, "ang"=>8736, "apos"=>39, "aring"=>229, "asymp"=>8776,
+ "atilde"=>227, "auml"=>228, "bdquo"=>8222, "beta"=>946, "brvbar"=>166,
+ "bull"=>8226, "cap"=>8745, "ccedil"=>231, "cedil"=>184, "cent"=>162,
+ "chi"=>967, "circ"=>710, "clubs"=>9827, "cong"=>8773, "copy"=>169,
+ "crarr"=>8629, "cup"=>8746, "curren"=>164, "dArr"=>8659, "dagger"=>8224,
+ "darr"=>8595, "deg"=>176, "delta"=>948, "diams"=>9830, "divide"=>247,
+ "eacute"=>233, "ecirc"=>234, "egrave"=>232, "empty"=>8709, "emsp"=>8195,
+ "ensp"=>8194, "epsilon"=>949, "equiv"=>8801, "eta"=>951, "eth"=>240,
+ "euml"=>235, "euro"=>8364, "exist"=>8707, "fnof"=>402, "forall"=>8704,
+ "frac12"=>189, "frac14"=>188, "frac34"=>190, "frasl"=>8260, "gamma"=>947,
+ "ge"=>8805, "gt"=>62, "hArr"=>8660, "harr"=>8596, "hearts"=>9829,
+ "hellip"=>8230, "iacute"=>237, "icirc"=>238, "iexcl"=>161, "igrave"=>236,
+ "image"=>8465, "infin"=>8734, "int"=>8747, "iota"=>953, "iquest"=>191,
+ "isin"=>8712, "iuml"=>239, "kappa"=>954, "lArr"=>8656, "lambda"=>955,
+ "lang"=>9001, "laquo"=>171, "larr"=>8592, "lceil"=>8968, "ldquo"=>8220,
+ "le"=>8804, "lfloor"=>8970, "lowast"=>8727, "loz"=>9674, "lrm"=>8206,
+ "lsaquo"=>8249, "lsquo"=>8216, "lt"=>60, "macr"=>175, "mdash"=>8212,
+ "micro"=>181, "middot"=>183, "minus"=>8722, "mu"=>956, "nabla"=>8711,
+ "nbsp"=>160, "ndash"=>8211, "ne"=>8800, "ni"=>8715, "not"=>172, "notin"=>8713,
+ "nsub"=>8836, "ntilde"=>241, "nu"=>957, "oacute"=>243, "ocirc"=>244,
+ "oelig"=>339, "ograve"=>242, "oline"=>8254, "omega"=>969, "omicron"=>959,
+ "oplus"=>8853, "or"=>8744, "ordf"=>170, "ordm"=>186, "oslash"=>248,
+ "otilde"=>245, "otimes"=>8855, "ouml"=>246, "para"=>182, "part"=>8706,
+ "permil"=>8240, "perp"=>8869, "phi"=>966, "pi"=>960, "piv"=>982,
+ "plusmn"=>177, "pound"=>163, "prime"=>8242, "prod"=>8719, "prop"=>8733,
+ "psi"=>968, "quot"=>34, "rArr"=>8658, "radic"=>8730, "rang"=>9002,
+ "raquo"=>187, "rarr"=>8594, "rceil"=>8969, "rdquo"=>8221, "real"=>8476,
+ "reg"=>174, "rfloor"=>8971, "rho"=>961, "rlm"=>8207, "rsaquo"=>8250,
+ "rsquo"=>8217, "sbquo"=>8218, "scaron"=>353, "sdot"=>8901, "sect"=>167,
+ "shy"=>173, "sigma"=>963, "sigmaf"=>962, "sim"=>8764, "spades"=>9824,
+ "sub"=>8834, "sube"=>8838, "sum"=>8721, "sup"=>8835, "sup1"=>185, "sup2"=>178,
+ "sup3"=>179, "supe"=>8839, "szlig"=>223, "tau"=>964, "there4"=>8756,
+ "theta"=>952, "thetasym"=>977, "thinsp"=>8201, "thorn"=>254, "tilde"=>732,
+ "times"=>215, "trade"=>8482, "uArr"=>8657, "uacute"=>250, "uarr"=>8593,
+ "ucirc"=>251, "ugrave"=>249, "uml"=>168, "upsih"=>978, "upsilon"=>965,
+ "uuml"=>252, "weierp"=>8472, "xi"=>958, "yacute"=>253, "yen"=>165,
+ "yuml"=>255, "zeta"=>950, "zwj"=>8205, "zwnj"=>8204}
+
+
+ NamedCharactersPattern = /\A(?-mix:AElig|Aacute|Acirc|Agrave|Alpha|Aring|Atilde|Auml|Beta|Ccedil|Chi|Dagger|Delta|ETH|Eacute|Ecirc|Egrave|Epsilon|Eta|Euml|Gamma|Iacute|Icirc|Igrave|Iota|Iuml|Kappa|Lambda|Mu|Ntilde|Nu|OElig|Oacute|Ocirc|Ograve|Omega|Omicron|Oslash|Otilde|Ouml|Phi|Pi|Prime|Psi|Rho|Scaron|Sigma|THORN|Tau|Theta|Uacute|Ucirc|Ugrave|Upsilon|Uuml|Xi|Yacute|Yuml|Zeta|aacute|acirc|acute|aelig|agrave|alefsym|alpha|amp|and|ang|apos|aring|asymp|atilde|auml|bdquo|beta|brvbar|bull|cap|ccedil|cedil|cent|chi|circ|clubs|cong|copy|crarr|cup|curren|dArr|dagger|darr|deg|delta|diams|divide|eacute|ecirc|egrave|empty|emsp|ensp|epsilon|equiv|eta|eth|euml|euro|exist|fnof|forall|frac12|frac14|frac34|frasl|gamma|ge|gt|hArr|harr|hearts|hellip|iacute|icirc|iexcl|igrave|image|infin|int|iota|iquest|isin|iuml|kappa|lArr|lambda|lang|laquo|larr|lceil|ldquo|le|lfloor|lowast|loz|lrm|lsaquo|lsquo|lt|macr|mdash|micro|middot|minus|mu|nabla|nbsp|ndash|ne|ni|not|notin|nsub|ntilde|nu|oacute|ocirc|oelig|ograve|oline|omega|omicron|oplus|or|ordf|ordm|oslash|otilde|otimes|ouml|para|part|permil|perp|phi|pi|piv|plusmn|pound|prime|prod|prop|psi|quot|rArr|radic|rang|raquo|rarr|rceil|rdquo|real|reg|rfloor|rho|rlm|rsaquo|rsquo|sbquo|scaron|sdot|sect|shy|sigma|sigmaf|sim|spades|sub|sube|sum|sup|sup1|sup2|sup3|supe|szlig|tau|there4|theta|thetasym|thinsp|thorn|tilde|times|trade|uArr|uacute|uarr|ucirc|ugrave|uml|upsih|upsilon|uuml|weierp|xi|yacute|yen|yuml|zeta|zwj|zwnj)\z/
+
+ ElementContent =
+{"h6"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "object"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "param", "pre", "q",
+ "s", "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "dl"=>["dd", "dt"],
+ "p"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "acronym"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "code"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "ul"=>["li"],
+ "tt"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "label"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "form"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "q"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "thead"=>["tr"],
+ "area"=>:EMPTY,
+ "td"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "title"=>[],
+ "dir"=>["li"],
+ "s"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "ol"=>["li"],
+ "hr"=>:EMPTY,
+ "applet"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "param", "pre", "q",
+ "s", "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "table"=>["caption", "col", "colgroup", "tbody", "tfoot", "thead", "tr"],
+ "legend"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "cite"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "a"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "html"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "base", "basefont", "bdo",
+ "big", "blockquote", "body", "br", "button", "center", "cite", "code",
+ "dfn", "dir", "div", "dl", "em", "fieldset", "font", "form", "h1", "h2",
+ "h3", "h4", "h5", "h6", "head", "hr", "i", "iframe", "img", "input",
+ "isindex", "kbd", "label", "map", "menu", "noframes", "noscript", "object",
+ "ol", "p", "pre", "q", "s", "samp", "script", "select", "small", "span",
+ "strike", "strong", "sub", "sup", "table", "textarea", "title", "tt", "u",
+ "ul", "var"],
+ "u"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "blockquote"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "center"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "b"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "base"=>:EMPTY,
+ "th"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "link"=>:EMPTY,
+ "var"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "samp"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "div"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "textarea"=>[],
+ "pre"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "head"=>["base", "isindex", "title"],
+ "span"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "br"=>:EMPTY,
+ "script"=>:CDATA,
+ "noframes"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "style"=>:CDATA,
+ "meta"=>:EMPTY,
+ "dt"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "option"=>[],
+ "kbd"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "big"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "tfoot"=>["tr"],
+ "sup"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "bdo"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "isindex"=>:EMPTY,
+ "dfn"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "fieldset"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "legend",
+ "map", "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "em"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "font"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "tbody"=>["tr"],
+ "noscript"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "li"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "col"=>:EMPTY,
+ "small"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "dd"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "i"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "menu"=>["li"],
+ "strong"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "basefont"=>:EMPTY,
+ "img"=>:EMPTY,
+ "optgroup"=>["option"],
+ "map"=>
+ ["address", "area", "blockquote", "center", "dir", "div", "dl", "fieldset",
+ "form", "h1", "h2", "h3", "h4", "h5", "h6", "hr", "isindex", "menu",
+ "noframes", "noscript", "ol", "p", "pre", "table", "ul"],
+ "h1"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "address"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "p", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "sub"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "param"=>:EMPTY,
+ "input"=>:EMPTY,
+ "h2"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "abbr"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "h3"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "strike"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "body"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "ins"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "button"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "h4"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "select"=>["optgroup", "option"],
+ "caption"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "colgroup"=>["col"],
+ "tr"=>["td", "th"],
+ "del"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"],
+ "h5"=>
+ ["a", "abbr", "acronym", "applet", "b", "basefont", "bdo", "big", "br",
+ "button", "cite", "code", "dfn", "em", "font", "i", "iframe", "img",
+ "input", "kbd", "label", "map", "object", "q", "s", "samp", "script",
+ "select", "small", "span", "strike", "strong", "sub", "sup", "textarea",
+ "tt", "u", "var"],
+ "iframe"=>
+ ["a", "abbr", "acronym", "address", "applet", "b", "basefont", "bdo", "big",
+ "blockquote", "br", "button", "center", "cite", "code", "dfn", "dir", "div",
+ "dl", "em", "fieldset", "font", "form", "h1", "h2", "h3", "h4", "h5", "h6",
+ "hr", "i", "iframe", "img", "input", "isindex", "kbd", "label", "map",
+ "menu", "noframes", "noscript", "object", "ol", "p", "pre", "q", "s",
+ "samp", "script", "select", "small", "span", "strike", "strong", "sub",
+ "sup", "table", "textarea", "tt", "u", "ul", "var"]}
+
+ ElementInclusions =
+{"head"=>["link", "meta", "object", "script", "style"], "body"=>["del", "ins"]}
+
+ ElementExclusions =
+{"button"=>
+ ["a", "button", "fieldset", "form", "iframe", "input", "isindex", "label",
+ "select", "textarea"],
+ "a"=>["a"],
+ "dir"=>
+ ["address", "blockquote", "center", "dir", "div", "dl", "fieldset", "form",
+ "h1", "h2", "h3", "h4", "h5", "h6", "hr", "isindex", "menu", "noframes",
+ "noscript", "ol", "p", "pre", "table", "ul"],
+ "title"=>["link", "meta", "object", "script", "style"],
+ "pre"=>
+ ["applet", "basefont", "big", "font", "img", "object", "small", "sub",
+ "sup"],
+ "form"=>["form"],
+ "menu"=>
+ ["address", "blockquote", "center", "dir", "div", "dl", "fieldset", "form",
+ "h1", "h2", "h3", "h4", "h5", "h6", "hr", "isindex", "menu", "noframes",
+ "noscript", "ol", "p", "pre", "table", "ul"],
+ "label"=>["label"]}
+
+ OmittedAttrName =
+{"h6"=>
+ {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "right"=>"align", "rtl"=>"dir"},
+ "object"=>
+ {"bottom"=>"align", "declare"=>"declare", "left"=>"align", "ltr"=>"dir",
+ "middle"=>"align", "right"=>"align", "rtl"=>"dir", "top"=>"align"},
+ "dl"=>{"compact"=>"compact", "ltr"=>"dir", "rtl"=>"dir"},
+ "p"=>
+ {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "right"=>"align", "rtl"=>"dir"},
+ "acronym"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "code"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "ul"=>
+ {"circle"=>"type", "compact"=>"compact", "disc"=>"type", "ltr"=>"dir",
+ "rtl"=>"dir", "square"=>"type"},
+ "tt"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "label"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "form"=>{"get"=>"method", "ltr"=>"dir", "post"=>"method", "rtl"=>"dir"},
+ "q"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "thead"=>
+ {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align",
+ "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"},
+ "area"=>
+ {"circle"=>"shape", "default"=>"shape", "ltr"=>"dir", "nohref"=>"nohref",
+ "poly"=>"shape", "rect"=>"shape", "rtl"=>"dir"},
+ "td"=>
+ {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align",
+ "char"=>"align", "col"=>"scope", "colgroup"=>"scope", "justify"=>"align",
+ "left"=>"align", "ltr"=>"dir", "middle"=>"valign", "nowrap"=>"nowrap",
+ "right"=>"align", "row"=>"scope", "rowgroup"=>"scope", "rtl"=>"dir",
+ "top"=>"valign"},
+ "title"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "dir"=>{"compact"=>"compact", "ltr"=>"dir", "rtl"=>"dir"},
+ "s"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "ol"=>{"compact"=>"compact", "ltr"=>"dir", "rtl"=>"dir"},
+ "hr"=>
+ {"center"=>"align", "left"=>"align", "ltr"=>"dir", "noshade"=>"noshade",
+ "right"=>"align", "rtl"=>"dir"},
+ "applet"=>
+ {"bottom"=>"align", "left"=>"align", "middle"=>"align", "right"=>"align",
+ "top"=>"align"},
+ "table"=>
+ {"above"=>"frame", "all"=>"rules", "below"=>"frame", "border"=>"frame",
+ "box"=>"frame", "center"=>"align", "cols"=>"rules", "groups"=>"rules",
+ "hsides"=>"frame", "left"=>"align", "lhs"=>"frame", "ltr"=>"dir",
+ "none"=>"rules", "rhs"=>"frame", "right"=>"align", "rows"=>"rules",
+ "rtl"=>"dir", "void"=>"frame", "vsides"=>"frame"},
+ "legend"=>
+ {"bottom"=>"align", "left"=>"align", "ltr"=>"dir", "right"=>"align",
+ "rtl"=>"dir", "top"=>"align"},
+ "cite"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "a"=>
+ {"circle"=>"shape", "default"=>"shape", "ltr"=>"dir", "poly"=>"shape",
+ "rect"=>"shape", "rtl"=>"dir"},
+ "html"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "u"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "blockquote"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "center"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "b"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "th"=>
+ {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align",
+ "char"=>"align", "col"=>"scope", "colgroup"=>"scope", "justify"=>"align",
+ "left"=>"align", "ltr"=>"dir", "middle"=>"valign", "nowrap"=>"nowrap",
+ "right"=>"align", "row"=>"scope", "rowgroup"=>"scope", "rtl"=>"dir",
+ "top"=>"valign"},
+ "link"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "var"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "samp"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "div"=>
+ {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "right"=>"align", "rtl"=>"dir"},
+ "textarea"=>
+ {"disabled"=>"disabled", "ltr"=>"dir", "readonly"=>"readonly", "rtl"=>"dir"},
+ "pre"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "head"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "span"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "br"=>{"all"=>"clear", "left"=>"clear", "none"=>"clear", "right"=>"clear"},
+ "script"=>{"defer"=>"defer"},
+ "noframes"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "style"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "meta"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "dt"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "option"=>
+ {"disabled"=>"disabled", "ltr"=>"dir", "rtl"=>"dir", "selected"=>"selected"},
+ "kbd"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "big"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "tfoot"=>
+ {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align",
+ "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"},
+ "sup"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "bdo"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "isindex"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "dfn"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "fieldset"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "em"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "font"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "tbody"=>
+ {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align",
+ "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"},
+ "noscript"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "li"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "col"=>
+ {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align",
+ "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"},
+ "small"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "dd"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "i"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "menu"=>{"compact"=>"compact", "ltr"=>"dir", "rtl"=>"dir"},
+ "strong"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "img"=>
+ {"bottom"=>"align", "ismap"=>"ismap", "left"=>"align", "ltr"=>"dir",
+ "middle"=>"align", "right"=>"align", "rtl"=>"dir", "top"=>"align"},
+ "optgroup"=>{"disabled"=>"disabled", "ltr"=>"dir", "rtl"=>"dir"},
+ "map"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "address"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "h1"=>
+ {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "right"=>"align", "rtl"=>"dir"},
+ "sub"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "param"=>{"data"=>"valuetype", "object"=>"valuetype", "ref"=>"valuetype"},
+ "input"=>
+ {"bottom"=>"align", "button"=>"type", "checkbox"=>"type",
+ "checked"=>"checked", "disabled"=>"disabled", "file"=>"type",
+ "hidden"=>"type", "image"=>"type", "ismap"=>"ismap", "left"=>"align",
+ "ltr"=>"dir", "middle"=>"align", "password"=>"type", "radio"=>"type",
+ "readonly"=>"readonly", "reset"=>"type", "right"=>"align", "rtl"=>"dir",
+ "submit"=>"type", "text"=>"type", "top"=>"align"},
+ "h2"=>
+ {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "right"=>"align", "rtl"=>"dir"},
+ "abbr"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "h3"=>
+ {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "right"=>"align", "rtl"=>"dir"},
+ "strike"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "body"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "ins"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "button"=>
+ {"button"=>"type", "disabled"=>"disabled", "ltr"=>"dir", "reset"=>"type",
+ "rtl"=>"dir", "submit"=>"type"},
+ "h4"=>
+ {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "right"=>"align", "rtl"=>"dir"},
+ "select"=>
+ {"disabled"=>"disabled", "ltr"=>"dir", "multiple"=>"multiple", "rtl"=>"dir"},
+ "caption"=>
+ {"bottom"=>"align", "left"=>"align", "ltr"=>"dir", "right"=>"align",
+ "rtl"=>"dir", "top"=>"align"},
+ "colgroup"=>
+ {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align",
+ "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"},
+ "tr"=>
+ {"baseline"=>"valign", "bottom"=>"valign", "center"=>"align",
+ "char"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "middle"=>"valign", "right"=>"align", "rtl"=>"dir", "top"=>"valign"},
+ "del"=>{"ltr"=>"dir", "rtl"=>"dir"},
+ "h5"=>
+ {"center"=>"align", "justify"=>"align", "left"=>"align", "ltr"=>"dir",
+ "right"=>"align", "rtl"=>"dir"},
+ "iframe"=>
+ {"0"=>"frameborder", "1"=>"frameborder", "auto"=>"scrolling",
+ "bottom"=>"align", "left"=>"align", "middle"=>"align", "no"=>"scrolling",
+ "right"=>"align", "top"=>"align", "yes"=>"scrolling"}}
+
+ # :startdoc:
+# The code above is auto-generated. Don't edit manually.
+end
diff --git a/vendor/gems/hpricot-0.6/lib/hpricot/inspect.rb b/vendor/gems/hpricot-0.6/lib/hpricot/inspect.rb
new file mode 100644
index 0000000..0af4d35
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/lib/hpricot/inspect.rb
@@ -0,0 +1,107 @@
+require 'pp'
+
+module Hpricot
+ # :stopdoc:
+ class Elements
+ def pretty_print(q)
+ q.object_group(self) { super }
+ end
+ alias inspect pretty_print_inspect
+ end
+
+ class Doc
+ def pretty_print(q)
+ q.object_group(self) { @children.each {|elt| q.breakable; q.pp elt } }
+ end
+ alias inspect pretty_print_inspect
+ end
+
+ class Elem
+ def pretty_print(q)
+ if empty?
+ q.group(1, '{emptyelem', '}') {
+ q.breakable; q.pp @stag
+ }
+ else
+ q.group(1, "{elem", "}") {
+ q.breakable; q.pp @stag
+ if @children
+ @children.each {|elt| q.breakable; q.pp elt }
+ end
+ if @etag
+ q.breakable; q.pp @etag
+ end
+ }
+ end
+ end
+ alias inspect pretty_print_inspect
+ end
+
+ module Leaf
+ def pretty_print(q)
+ q.group(1, '{', '}') {
+ q.text self.class.name.sub(/.*::/,'').downcase
+ if rs = @raw_string
+ rs.scan(/[^\r\n]*(?:\r\n?|\n|[^\r\n]\z)/) {|line|
+ q.breakable
+ q.pp line
+ }
+ elsif self.respond_to? :to_s
+ q.breakable
+ q.text self.to_s
+ end
+ }
+ end
+ alias inspect pretty_print_inspect
+ end
+
+ class STag
+ def pretty_print(q)
+ q.group(1, '<', '>') {
+ q.text @name
+
+ if @raw_attributes
+ @raw_attributes.each {|n, t|
+ q.breakable
+ if t
+ q.text "#{n}=\"#{Hpricot.uxs(t)}\""
+ else
+ q.text n
+ end
+ }
+ end
+ }
+ end
+ alias inspect pretty_print_inspect
+ end
+
+ class ETag
+ def pretty_print(q)
+ q.group(1, '', '>') {
+ q.text @name
+ }
+ end
+ alias inspect pretty_print_inspect
+ end
+
+ class Text
+ def pretty_print(q)
+ q.text @content.dump
+ end
+ end
+
+ class BogusETag
+ def pretty_print(q)
+ q.group(1, '{', '}') {
+ q.text self.class.name.sub(/.*::/,'').downcase
+ if rs = @raw_string
+ q.breakable
+ q.text rs
+ else
+ q.text "#{@name}>"
+ end
+ }
+ end
+ end
+ # :startdoc:
+end
diff --git a/vendor/gems/hpricot-0.6/lib/hpricot/modules.rb b/vendor/gems/hpricot-0.6/lib/hpricot/modules.rb
new file mode 100644
index 0000000..e96b922
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/lib/hpricot/modules.rb
@@ -0,0 +1,37 @@
+module Hpricot
+ class Name; include Hpricot end
+ class Context; include Hpricot end
+
+ # :stopdoc:
+ module Tag; include Hpricot end
+ class STag; include Tag end
+ class ETag; include Tag end
+ # :startdoc:
+
+ module Node; include Hpricot end
+ module Container; include Node end
+ class Doc; include Container end
+ class Elem; include Container end
+ module Leaf; include Node end
+ class Text; include Leaf end
+ class XMLDecl; include Leaf end
+ class DocType; include Leaf end
+ class ProcIns; include Leaf end
+ class Comment; include Leaf end
+ class BogusETag; include Leaf end
+
+ module Traverse end
+ module Container::Trav; include Traverse end
+ module Leaf::Trav; include Traverse end
+ class Doc; module Trav; include Container::Trav end; include Trav end
+ class Elem; module Trav; include Container::Trav end; include Trav end
+ class Text; module Trav; include Leaf::Trav end; include Trav end
+ class XMLDecl; module Trav; include Leaf::Trav end; include Trav end
+ class DocType; module Trav; include Leaf::Trav end; include Trav end
+ class ProcIns; module Trav; include Leaf::Trav end; include Trav end
+ class Comment; module Trav; include Leaf::Trav end; include Trav end
+ class BogusETag; module Trav; include Leaf::Trav end; include Trav end
+
+ class Error < StandardError; end
+end
+
diff --git a/vendor/gems/hpricot-0.6/lib/hpricot/parse.rb b/vendor/gems/hpricot-0.6/lib/hpricot/parse.rb
new file mode 100644
index 0000000..47ed217
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/lib/hpricot/parse.rb
@@ -0,0 +1,297 @@
+require 'hpricot/htmlinfo'
+
+def Hpricot(input = nil, opts = {}, &blk)
+ Hpricot.parse(input, opts, &blk)
+end
+
+module Hpricot
+ # Exception class used for any errors related to deficiencies in the system when
+ # handling the character encodings of a document.
+ class EncodingError < StandardError; end
+
+ # Hpricot.parse parses input and return a document tree.
+ # represented by Hpricot::Doc.
+ def Hpricot.parse(input = nil, opts = {}, &blk)
+ Doc.new(make(input, opts, &blk))
+ end
+
+ # Hpricot::XML parses input, disregarding all the HTML rules
+ # and returning a document tree.
+ def Hpricot.XML(input, opts = {})
+ Doc.new(make(input, opts.merge(:xml => true)))
+ end
+
+ # :stopdoc:
+
+ def Hpricot.make(input = nil, opts = {}, &blk)
+ opts = {:fixup_tags => false}.merge(opts)
+ unless input or blk
+ raise ArgumentError, "An Hpricot document must be built from an input source (a String) or a block."
+ end
+
+ conv = opts[:xml] ? :to_s : :downcase
+
+ fragment =
+ if input
+ case opts[:encoding]
+ when nil
+ when 'utf-8'
+ unless defined? Encoding::Character::UTF8
+ raise EncodingError, "The ruby-character-encodings library could not be found for utf-8 mode."
+ end
+ else
+ raise EncodingError, "No encoding option `#{opts[:encoding]}' is available."
+ end
+
+ if opts[:xhtml_strict]
+ opts[:fixup_tags] = true
+ end
+
+ stack = [[nil, nil, [], [], [], []]]
+ Hpricot.scan(input) do |token|
+ if stack.last[5] == :CDATA and ![:procins, :comment, :cdata].include?(token[0]) and
+ !(token[0] == :etag and token[1].casecmp(stack.last[0]).zero?)
+ token[0] = :text
+ token[1] = token[3] if token[3]
+ end
+
+ if !opts[:xml] and token[0] == :emptytag
+ token[1] = token[1].send(conv)
+ if ElementContent[token[1].downcase] != :EMPTY
+ token[0] = :stag
+ end
+ end
+
+ # TODO: downcase instead when parsing attributes?
+ if !opts[:xml] and token[2].is_a?(Hash)
+ token[2] = token[2].inject({}) { |hsh,(k,v)| hsh[k.downcase] = v; hsh }
+ end
+
+ case token[0]
+ when :stag
+ case opts[:encoding] when 'utf-8'
+ token.map! { |str| u(str) if str.is_a? String }
+ end
+
+ stagname = token[0] = token[1] = token[1].send(conv)
+ if ElementContent[stagname] == :EMPTY and !opts[:xml]
+ token[0] = :emptytag
+ stack.last[2] << token
+ else
+ unless opts[:xml]
+ if opts[:fixup_tags]
+ # obey the tag rules set up by the current element
+ if ElementContent.has_key? stagname
+ trans = nil
+ (stack.length-1).downto(0) do |i|
+ untags = stack[i][5]
+ break unless untags.include? stagname
+ # puts "** ILLEGAL #{stagname} IN #{stack[i][0]}"
+ trans = i
+ end
+ if trans.to_i > 1
+ eles = stack.slice!(trans..-1)
+ stack.last[2] += eles
+ # puts "** TRANSPLANTED #{stagname} TO #{stack.last[0]}"
+ end
+ elsif opts[:xhtml_strict]
+ token[2] = {'class' => stagname}
+ stagname = token[0] = "div"
+ end
+ end
+
+ # setup tag rules for inside this element
+ if ElementContent[stagname] == :CDATA
+ uncontainable_tags = :CDATA
+ elsif opts[:fixup_tags]
+ possible_tags = ElementContent[stagname]
+ excluded_tags, included_tags = stack.last[3..4]
+ if possible_tags
+ excluded_tags = excluded_tags | (ElementExclusions[stagname] || [])
+ included_tags = included_tags | (ElementInclusions[stagname] || [])
+ containable_tags = (possible_tags | included_tags) - excluded_tags
+ uncontainable_tags = ElementContent.keys - containable_tags
+ else
+ # If the tagname is unknown, it is assumed that any element
+ # except excluded can be contained.
+ uncontainable_tags = excluded_tags
+ end
+ end
+ end
+ unless opts[:xml]
+ case token[2] when Hash
+ token[2] = token[2].inject({}) { |hsh,(k,v)| hsh[k.downcase] = v; hsh }
+ end
+ end
+ stack << [stagname, token, [], excluded_tags, included_tags, uncontainable_tags]
+ end
+ when :etag
+ etagname = token[0] = token[1].send(conv)
+ if opts[:xhtml_strict] and not ElementContent.has_key? etagname
+ etagname = token[0] = "div"
+ end
+ matched_elem = nil
+ (stack.length-1).downto(0) do |i|
+ stagname, = stack[i]
+ if stagname == etagname
+ matched_elem = stack[i]
+ stack[i][1] += token
+ eles = stack.slice!((i+1)..-1)
+ stack.last[2] += eles
+ break
+ end
+ end
+ unless matched_elem
+ stack.last[2] << [:bogus_etag, token.first, token.last]
+ else
+ ele = stack.pop
+ stack.last[2] << ele
+ end
+ when :text
+ l = stack.last[2].last
+ if l and l[0] == :text
+ l[1] += token[1]
+ else
+ stack.last[2] << token
+ end
+ else
+ stack.last[2] << token
+ end
+ end
+
+ while 1 < stack.length
+ ele = stack.pop
+ stack.last[2] << ele
+ end
+
+ structure_list = stack[0][2]
+ structure_list.map {|s| build_node(s, opts) }
+ elsif blk
+ Hpricot.build(&blk).children
+ end
+ end
+
+ def Hpricot.build_node(structure, opts = {})
+ case structure[0]
+ when String
+ tagname, _, attrs, sraw, _, _, _, eraw = structure[1]
+ children = structure[2]
+ etag = eraw && ETag.parse(tagname, eraw)
+ stag = STag.parse(tagname, attrs, sraw, true)
+ if !children.empty? || etag
+ Elem.new(stag,
+ children.map {|c| build_node(c, opts) },
+ etag)
+ else
+ Elem.new(stag)
+ end
+ when :text
+ Text.parse_pcdata(structure[1])
+ when :emptytag
+ Elem.new(STag.parse(structure[1], structure[2], structure[3], false))
+ when :bogus_etag
+ BogusETag.parse(structure[1], structure[2])
+ when :xmldecl
+ XMLDecl.parse(structure[2], structure[3])
+ when :doctype
+ if opts[:xhtml_strict]
+ structure[2]['system_id'] = "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"
+ structure[2]['public_id'] = "-//W3C//DTD XHTML 1.0 Strict//EN"
+ end
+ DocType.parse(structure[1], structure[2], structure[3])
+ when :procins
+ ProcIns.parse(structure[1])
+ when :comment
+ Comment.parse(structure[1])
+ when :cdata_content
+ Text.parse_cdata_content(structure[1])
+ when :cdata
+ Text.parse_cdata_section(structure[1])
+ else
+ raise Exception, "[bug] unknown structure: #{structure.inspect}"
+ end
+ end
+
+ def STag.parse(qname, attrs, raw_string, is_stag)
+ result = STag.new(qname, attrs)
+ result.raw_string = raw_string
+ result
+ end
+
+ def ETag.parse(qname, raw_string)
+ result = self.new(qname)
+ result.raw_string = raw_string
+ result
+ end
+
+ def BogusETag.parse(qname, raw_string)
+ result = self.new(qname)
+ result.raw_string = raw_string
+ result
+ end
+
+ def Text.parse_pcdata(raw_string)
+ result = Text.new(raw_string)
+ result
+ end
+
+ def Text.parse_cdata_content(raw_string)
+ result = CData.new(raw_string)
+ result
+ end
+
+ def Text.parse_cdata_section(content)
+ result = CData.new(content)
+ result
+ end
+
+ def XMLDecl.parse(attrs, raw_string)
+ attrs ||= {}
+ version = attrs['version']
+ encoding = attrs['encoding']
+ case attrs['standalone']
+ when 'yes'
+ standalone = true
+ when 'no'
+ standalone = false
+ else
+ standalone = nil
+ end
+
+ result = XMLDecl.new(version, encoding, standalone)
+ result.raw_string = raw_string
+ result
+ end
+
+ def DocType.parse(root_element_name, attrs, raw_string)
+ if attrs
+ public_identifier = attrs['public_id']
+ system_identifier = attrs['system_id']
+ end
+
+ root_element_name = root_element_name.downcase
+
+ result = DocType.new(root_element_name, public_identifier, system_identifier)
+ result.raw_string = raw_string
+ result
+ end
+
+ def ProcIns.parse(raw_string)
+ _, target, content = *raw_string.match(/\A<\?(\S+)\s+(.+)/m)
+ result = ProcIns.new(target, content)
+ result
+ end
+
+ def Comment.parse(content)
+ result = Comment.new(content)
+ result
+ end
+
+ module Pat
+ NameChar = /[-A-Za-z0-9._:]/
+ Name = /[A-Za-z_:]#{NameChar}*/
+ Nmtoken = /#{NameChar}+/
+ end
+
+ # :startdoc:
+end
diff --git a/vendor/gems/hpricot-0.6/lib/hpricot/tag.rb b/vendor/gems/hpricot-0.6/lib/hpricot/tag.rb
new file mode 100644
index 0000000..7fe5479
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/lib/hpricot/tag.rb
@@ -0,0 +1,228 @@
+module Hpricot
+ # :stopdoc:
+
+ class Doc
+ attr_accessor :children
+ def initialize(children = [])
+ @children = children ? children.each { |c| c.parent = self } : []
+ end
+ def output(out, opts = {})
+ @children.each do |n|
+ n.output(out, opts)
+ end
+ out
+ end
+ def altered!; end
+ end
+
+ class BaseEle
+ attr_accessor :raw_string, :parent
+ def html_quote(str)
+ "\"" + str.gsub('"', '\\"') + "\""
+ end
+ def if_output(opts)
+ if opts[:preserve] and not @raw_string.nil?
+ @raw_string
+ else
+ yield opts
+ end
+ end
+ def pathname; self.name end
+ def altered!
+ @raw_string = nil
+ end
+ def self.alterable(*fields)
+ attr_accessor(*fields)
+ fields.each do |f|
+ define_method("#{f}=") do |v|
+ altered!
+ instance_variable_set("@#{f}", v)
+ end
+ end
+ end
+ end
+
+ class Elem
+ attr_accessor :stag, :etag, :children
+ def initialize(stag, children=nil, etag=nil)
+ @stag, @etag = stag, etag
+ @children = children ? children.each { |c| c.parent = self } : []
+ end
+ def empty?; @children.empty? end
+ [:name, :raw_attributes, :parent, :altered!].each do |m|
+ [m, "#{m}="].each { |m2| define_method(m2) { |*a| [@etag, @stag].inject { |_,t| t.send(m2, *a) if t and t.respond_to?(m2) } } }
+ end
+ def attributes
+ if raw_attributes
+ raw_attributes.inject({}) do |hsh, (k, v)|
+ hsh[k] = Hpricot.uxs(v)
+ hsh
+ end
+ end
+ end
+ def to_plain_text
+ if self.name == 'br'
+ "\n"
+ elsif self.name == 'p'
+ "\n\n" + super + "\n\n"
+ elsif self.name == 'a' and self.has_attribute?('href')
+ "#{super} [#{self['href']}]"
+ elsif self.name == 'img' and self.has_attribute?('src')
+ "[img:#{self['src']}]"
+ else
+ super
+ end
+ end
+ def pathname; self.name end
+ def output(out, opts = {})
+ if empty? and ElementContent[@stag.name] == :EMPTY
+ @stag.output(out, opts.merge(:style => :empty))
+ else
+ @stag.output(out, opts)
+ @children.each { |n| n.output(out, opts) }
+ if @etag
+ @etag.output(out, opts)
+ elsif !opts[:preserve]
+ ETag.new(@stag.name).output(out, opts)
+ end
+ end
+ out
+ end
+ end
+
+ class STag < BaseEle
+ def initialize(name, attributes=nil)
+ @name = name.to_s
+ @raw_attributes = attributes || {}
+ end
+ alterable :name, :raw_attributes
+ def attributes_as_html
+ if @raw_attributes
+ @raw_attributes.map do |aname, aval|
+ " #{aname}" +
+ (aval ? "=\"#{aval}\"" : "")
+ end.join
+ end
+ end
+ def output(out, opts = {})
+ out <<
+ if_output(opts) do
+ "<#{@name}#{attributes_as_html}" +
+ (opts[:style] == :empty ? " /" : "") +
+ ">"
+ end
+ end
+ end
+
+ class ETag < BaseEle
+ def initialize(qualified_name)
+ @name = qualified_name.to_s
+ end
+ alterable :name
+ def output(out, opts = {})
+ out <<
+ if_output(opts) do
+ "#{@name}>"
+ end
+ end
+ end
+
+ class BogusETag < ETag
+ def output(out, opts = {}); out << if_output(opts) { '' }; end
+ end
+
+ class Text < BaseEle
+ def initialize(text)
+ @content = text
+ end
+ alterable :content
+ def pathname; "text()" end
+ def to_s
+ Hpricot.uxs(@content)
+ end
+ alias_method :inner_text, :to_s
+ alias_method :to_plain_text, :to_s
+ def output(out, opts = {})
+ out <<
+ if_output(opts) do
+ @content
+ end
+ end
+ end
+
+ class CData < Text
+ alias_method :to_s, :content
+ alias_method :to_plain_text, :content
+ def output(out, opts = {})
+ out <<
+ if_output(opts) do
+ ""
+ end
+ end
+ end
+
+ class XMLDecl < BaseEle
+ def initialize(version, encoding, standalone)
+ @version, @encoding, @standalone = version, encoding, standalone
+ end
+ alterable :version, :encoding, :standalone
+ def pathname; "xmldecl()" end
+ def output(out, opts = {})
+ out <<
+ if_output(opts) do
+ ""
+ end
+ end
+ end
+
+ class DocType < BaseEle
+ def initialize(target, pubid, sysid)
+ @target, @public_id, @system_id = target, pubid, sysid
+ end
+ alterable :target, :public_id, :system_id
+ def pathname; "doctype()" end
+ def output(out, opts = {})
+ out <<
+ if_output(opts) do
+ ""
+ end
+ end
+ end
+
+ class ProcIns < BaseEle
+ def initialize(target, content)
+ @target, @content = target, content
+ end
+ def pathname; "procins()" end
+ alterable :target, :content
+ def output(out, opts = {})
+ out <<
+ if_output(opts) do
+ "#{@target}" +
+ (@content ? " #{@content}" : "") +
+ "?>"
+ end
+ end
+ end
+
+ class Comment < BaseEle
+ def initialize(content)
+ @content = content
+ end
+ def pathname; "comment()" end
+ alterable :content
+ def output(out, opts = {})
+ out <<
+ if_output(opts) do
+ ""
+ end
+ end
+ end
+
+ # :startdoc:
+end
diff --git a/vendor/gems/hpricot-0.6/lib/hpricot/tags.rb b/vendor/gems/hpricot-0.6/lib/hpricot/tags.rb
new file mode 100644
index 0000000..6c2db5f
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/lib/hpricot/tags.rb
@@ -0,0 +1,164 @@
+module Hpricot
+
+ FORM_TAGS = [ :form, :input, :select, :textarea ]
+ SELF_CLOSING_TAGS = [ :base, :meta, :link, :hr, :br, :param, :img, :area, :input, :col ]
+
+ # Common sets of attributes.
+ AttrCore = [:id, :class, :style, :title]
+ AttrI18n = [:lang, 'xml:lang'.intern, :dir]
+ AttrEvents = [:onclick, :ondblclick, :onmousedown, :onmouseup, :onmouseover, :onmousemove,
+ :onmouseout, :onkeypress, :onkeydown, :onkeyup]
+ AttrFocus = [:accesskey, :tabindex, :onfocus, :onblur]
+ AttrHAlign = [:align, :char, :charoff]
+ AttrVAlign = [:valign]
+ Attrs = AttrCore + AttrI18n + AttrEvents
+
+ # All the tags and attributes from XHTML 1.0 Strict
+ class XHTMLStrict
+ class << self
+ attr_accessor :tags, :tagset, :forms, :self_closing, :doctype
+ end
+ @doctype = ["-//W3C//DTD XHTML 1.0 Strict//EN", "DTD/xhtml1-strict.dtd"]
+ @tagset = {
+ :html => AttrI18n + [:id, :xmlns],
+ :head => AttrI18n + [:id, :profile],
+ :title => AttrI18n + [:id],
+ :base => [:href, :id],
+ :meta => AttrI18n + [:id, :http, :name, :content, :scheme, 'http-equiv'.intern],
+ :link => Attrs + [:charset, :href, :hreflang, :type, :rel, :rev, :media],
+ :style => AttrI18n + [:id, :type, :media, :title, 'xml:space'.intern],
+ :script => [:id, :charset, :type, :src, :defer, 'xml:space'.intern],
+ :noscript => Attrs,
+ :body => Attrs + [:onload, :onunload],
+ :div => Attrs,
+ :p => Attrs,
+ :ul => Attrs,
+ :ol => Attrs,
+ :li => Attrs,
+ :dl => Attrs,
+ :dt => Attrs,
+ :dd => Attrs,
+ :address => Attrs,
+ :hr => Attrs,
+ :pre => Attrs + ['xml:space'.intern],
+ :blockquote => Attrs + [:cite],
+ :ins => Attrs + [:cite, :datetime],
+ :del => Attrs + [:cite, :datetime],
+ :a => Attrs + AttrFocus + [:charset, :type, :name, :href, :hreflang, :rel, :rev, :shape, :coords],
+ :span => Attrs,
+ :bdo => AttrCore + AttrEvents + [:lang, 'xml:lang'.intern, :dir],
+ :br => AttrCore,
+ :em => Attrs,
+ :strong => Attrs,
+ :dfn => Attrs,
+ :code => Attrs,
+ :samp => Attrs,
+ :kbd => Attrs,
+ :var => Attrs,
+ :cite => Attrs,
+ :abbr => Attrs,
+ :acronym => Attrs,
+ :q => Attrs + [:cite],
+ :sub => Attrs,
+ :sup => Attrs,
+ :tt => Attrs,
+ :i => Attrs,
+ :b => Attrs,
+ :big => Attrs,
+ :small => Attrs,
+ :object => Attrs + [:declare, :classid, :codebase, :data, :type, :codetype, :archive, :standby, :height, :width, :usemap, :name, :tabindex],
+ :param => [:id, :name, :value, :valuetype, :type],
+ :img => Attrs + [:src, :alt, :longdesc, :height, :width, :usemap, :ismap],
+ :map => AttrI18n + AttrEvents + [:id, :class, :style, :title, :name],
+ :area => Attrs + AttrFocus + [:shape, :coords, :href, :nohref, :alt],
+ :form => Attrs + [:action, :method, :enctype, :onsubmit, :onreset, :accept, :accept],
+ :label => Attrs + [:for, :accesskey, :onfocus, :onblur],
+ :input => Attrs + AttrFocus + [:type, :name, :value, :checked, :disabled, :readonly, :size, :maxlength, :src, :alt, :usemap, :onselect, :onchange, :accept],
+ :select => Attrs + [:name, :size, :multiple, :disabled, :tabindex, :onfocus, :onblur, :onchange],
+ :optgroup => Attrs + [:disabled, :label],
+ :option => Attrs + [:selected, :disabled, :label, :value],
+ :textarea => Attrs + AttrFocus + [:name, :rows, :cols, :disabled, :readonly, :onselect, :onchange],
+ :fieldset => Attrs,
+ :legend => Attrs + [:accesskey],
+ :button => Attrs + AttrFocus + [:name, :value, :type, :disabled],
+ :table => Attrs + [:summary, :width, :border, :frame, :rules, :cellspacing, :cellpadding],
+ :caption => Attrs,
+ :colgroup => Attrs + AttrHAlign + AttrVAlign + [:span, :width],
+ :col => Attrs + AttrHAlign + AttrVAlign + [:span, :width],
+ :thead => Attrs + AttrHAlign + AttrVAlign,
+ :tfoot => Attrs + AttrHAlign + AttrVAlign,
+ :tbody => Attrs + AttrHAlign + AttrVAlign,
+ :tr => Attrs + AttrHAlign + AttrVAlign,
+ :th => Attrs + AttrHAlign + AttrVAlign + [:abbr, :axis, :headers, :scope, :rowspan, :colspan],
+ :td => Attrs + AttrHAlign + AttrVAlign + [:abbr, :axis, :headers, :scope, :rowspan, :colspan],
+ :h1 => Attrs,
+ :h2 => Attrs,
+ :h3 => Attrs,
+ :h4 => Attrs,
+ :h5 => Attrs,
+ :h6 => Attrs
+ }
+
+ @tags = @tagset.keys
+ @forms = @tags & FORM_TAGS
+ @self_closing = @tags & SELF_CLOSING_TAGS
+ end
+
+ # Additional tags found in XHTML 1.0 Transitional
+ class XHTMLTransitional
+ class << self
+ attr_accessor :tags, :tagset, :forms, :self_closing, :doctype
+ end
+ @doctype = ["-//W3C//DTD XHTML 1.0 Transitional//EN", "DTD/xhtml1-transitional.dtd"]
+ @tagset = XHTMLStrict.tagset.merge \
+ :strike => Attrs,
+ :center => Attrs,
+ :dir => Attrs + [:compact],
+ :noframes => Attrs,
+ :basefont => [:id, :size, :color, :face],
+ :u => Attrs,
+ :menu => Attrs + [:compact],
+ :iframe => AttrCore + [:longdesc, :name, :src, :frameborder, :marginwidth, :marginheight, :scrolling, :align, :height, :width],
+ :font => AttrCore + AttrI18n + [:size, :color, :face],
+ :s => Attrs,
+ :applet => AttrCore + [:codebase, :archive, :code, :object, :alt, :name, :width, :height, :align, :hspace, :vspace],
+ :isindex => AttrCore + AttrI18n + [:prompt]
+
+ # Additional attributes found in XHTML 1.0 Transitional
+ { :script => [:language],
+ :a => [:target],
+ :td => [:bgcolor, :nowrap, :width, :height],
+ :p => [:align],
+ :h5 => [:align],
+ :h3 => [:align],
+ :li => [:type, :value],
+ :div => [:align],
+ :pre => [:width],
+ :body => [:background, :bgcolor, :text, :link, :vlink, :alink],
+ :ol => [:type, :compact, :start],
+ :h4 => [:align],
+ :h2 => [:align],
+ :object => [:align, :border, :hspace, :vspace],
+ :img => [:name, :align, :border, :hspace, :vspace],
+ :link => [:target],
+ :legend => [:align],
+ :dl => [:compact],
+ :input => [:align],
+ :h6 => [:align],
+ :hr => [:align, :noshade, :size, :width],
+ :base => [:target],
+ :ul => [:type, :compact],
+ :br => [:clear],
+ :form => [:name, :target],
+ :area => [:target],
+ :h1 => [:align]
+ }.each do |k, v|
+ @tagset[k] += v
+ end
+
+ @tags = @tagset.keys
+ @forms = @tags & FORM_TAGS
+ @self_closing = @tags & SELF_CLOSING_TAGS
+ end
+
+end
diff --git a/vendor/gems/hpricot-0.6/lib/hpricot/traverse.rb b/vendor/gems/hpricot-0.6/lib/hpricot/traverse.rb
new file mode 100644
index 0000000..4ccb853
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/lib/hpricot/traverse.rb
@@ -0,0 +1,821 @@
+require 'hpricot/elements'
+require 'uri'
+
+module Hpricot
+ module Traverse
+ # Is this object the enclosing HTML or XML document?
+ def doc?() Doc::Trav === self end
+ # Is this object an HTML or XML element?
+ def elem?() Elem::Trav === self end
+ # Is this object an HTML text node?
+ def text?() Text::Trav === self end
+ # Is this object an XML declaration?
+ def xmldecl?() XMLDecl::Trav === self end
+ # Is this object a doctype tag?
+ def doctype?() DocType::Trav === self end
+ # Is this object an XML processing instruction?
+ def procins?() ProcIns::Trav === self end
+ # Is this object a comment?
+ def comment?() Comment::Trav === self end
+ # Is this object a stranded end tag?
+ def bogusetag?() BogusETag::Trav === self end
+
+ # Builds an HTML string from this node and its contents.
+ # If you need to write to a stream, try calling output(io)
+ # as a method on this object.
+ def to_html
+ output("")
+ end
+ alias_method :to_s, :to_html
+
+ # Attempts to preserve the original HTML of the document, only
+ # outputing new tags for elements which have changed.
+ def to_original_html
+ output("", :preserve => true)
+ end
+
+ def index(name)
+ i = 0
+ return i if name == "*"
+ children.each do |x|
+ return i if (x.respond_to?(:name) and name == x.name) or
+ (x.text? and name == "text()")
+ i += 1
+ end
+ -1
+ end
+
+ # Puts together an array of neighboring nodes based on their proximity
+ # to this node. So, for example, to get the next node, you could use
+ # nodes_at(1). Or, to get the previous node, use nodes_at(1).
+ #
+ # This method also accepts ranges and sets of numbers.
+ #
+ # ele.nodes_at(-3..-1, 1..3) # gets three nodes before and three after
+ # ele.nodes_at(1, 5, 7) # gets three nodes at offsets below the current node
+ # ele.nodes_at(0, 5..6) # the current node and two others
+ def nodes_at(*pos)
+ sib = parent.children
+ i, si = 0, sib.index(self)
+ pos.map! do |r|
+ if r.is_a?(Range) and r.begin.is_a?(String)
+ r = Range.new(parent.index(r.begin)-si, parent.index(r.end)-si, r.exclude_end?)
+ end
+ r
+ end
+ p pos
+ Elements[*
+ sib.select do |x|
+ sel =
+ case i - si when *pos
+ true
+ end
+ i += 1
+ sel
+ end
+ ]
+ end
+
+ # Returns the node neighboring this node to the south: just below it.
+ # This method includes text nodes and comments and such.
+ def next
+ sib = parent.children
+ sib[sib.index(self) + 1] if parent
+ end
+ alias_method :next_node, :next
+
+ # Returns to node neighboring this node to the north: just above it.
+ # This method includes text nodes and comments and such.
+ def previous
+ sib = parent.children
+ x = sib.index(self) - 1
+ sib[x] if sib and x >= 0
+ end
+ alias_method :previous_node, :previous
+
+ # Find all preceding nodes.
+ def preceding
+ sibs = parent.children
+ si = sibs.index(self)
+ return Elements[*sibs[0...si]]
+ end
+
+ # Find all nodes which follow the current one.
+ def following
+ sibs = parent.children
+ si = sibs.index(self) + 1
+ return Elements[*sibs[si...sibs.length]]
+ end
+
+ # Adds elements immediately after this element, contained in the +html+ string.
+ def after(html = nil, &blk)
+ parent.insert_after(Hpricot.make(html, &blk), self)
+ end
+
+ # Adds elements immediately before this element, contained in the +html+ string.
+ def before(html = nil, &blk)
+ parent.insert_before(Hpricot.make(html, &blk), self)
+ end
+
+
+ # Replace this element and its contents with the nodes contained
+ # in the +html+ string.
+ def swap(html = nil, &blk)
+ parent.altered!
+ parent.replace_child(self, Hpricot.make(html, &blk))
+ end
+
+ def get_subnode(*indexes)
+ n = self
+ indexes.each {|index|
+ n = n.get_subnode_internal(index)
+ }
+ n
+ end
+
+ # Builds a string from the text contained in this node. All
+ # HTML elements are removed.
+ def to_plain_text
+ if respond_to? :children
+ children.map { |x| x.to_plain_text }.join.strip.gsub(/\n{2,}/, "\n\n")
+ end
+ end
+
+ # Builds a string from the text contained in this node. All
+ # HTML elements are removed.
+ def inner_text
+ if respond_to? :children
+ children.map { |x| x.inner_text }.join
+ end
+ end
+ alias_method :innerText, :inner_text
+
+ # Builds an HTML string from the contents of this node.
+ def html(inner = nil, &blk)
+ if inner or blk
+ altered!
+ case inner
+ when Array
+ self.children = inner
+ else
+ self.children = Hpricot.make(inner, &blk)
+ end
+ reparent self.children
+ else
+ if respond_to? :children
+ children.map { |x| x.output("") }.join
+ end
+ end
+ end
+ alias_method :inner_html, :html
+ alias_method :innerHTML, :inner_html
+
+ # Inserts new contents into the current node, based on
+ # the HTML contained in string +inner+.
+ def inner_html=(inner)
+ html(inner || [])
+ end
+ alias_method :innerHTML=, :inner_html=
+
+ def reparent(nodes)
+ altered!
+ [*nodes].each { |e| e.parent = self }
+ end
+ private :reparent
+
+ def clean_path(path)
+ path.gsub(/^\s+|\s+$/, '')
+ end
+
+ # Builds a unique XPath string for this node, from the
+ # root of the document containing it.
+ def xpath
+ if elem? and has_attribute? 'id'
+ "//#{self.name}[@id='#{get_attribute('id')}']"
+ else
+ sim, id = 0, 0, 0
+ parent.children.each do |e|
+ id = sim if e == self
+ sim += 1 if e.pathname == self.pathname
+ end
+ p = File.join(parent.xpath, self.pathname)
+ p += "[#{id+1}]" if sim >= 2
+ p
+ end
+ end
+
+ # Builds a unique CSS string for this node, from the
+ # root of the document containing it.
+ def css_path
+ if elem? and has_attribute? 'id'
+ "##{get_attribute('id')}"
+ else
+ sim, i, id = 0, 0, 0
+ parent.children.each do |e|
+ id = sim if e == self
+ sim += 1 if e.pathname == self.pathname
+ end
+ p = parent.css_path
+ p = p ? "#{p} > #{self.pathname}" : self.pathname
+ p += ":nth(#{id})" if sim >= 2
+ p
+ end
+ end
+
+ def node_position
+ parent.children.index(self)
+ end
+
+ def position
+ parent.children_of_type(self.pathname).index(self)
+ end
+
+ # Searches this node for all elements matching
+ # the CSS or XPath +expr+. Returns an Elements array
+ # containing the matching nodes. If +blk+ is given, it
+ # is used to iterate through the matching set.
+ def search(expr, &blk)
+ if Range === expr
+ return Elements.expand(at(expr.begin), at(expr.end), expr.exclude_end?)
+ end
+ last = nil
+ nodes = [self]
+ done = []
+ expr = expr.to_s
+ hist = []
+ until expr.empty?
+ expr = clean_path(expr)
+ expr.gsub!(%r!^//!, '')
+
+ case expr
+ when %r!^/?\.\.!
+ last = expr = $'
+ nodes.map! { |node| node.parent }
+ when %r!^[>/]\s*!
+ last = expr = $'
+ nodes = Elements[*nodes.map { |node| node.children if node.respond_to? :children }.flatten.compact]
+ when %r!^\+!
+ last = expr = $'
+ nodes.map! do |node|
+ siblings = node.parent.children
+ siblings[siblings.index(node)+1]
+ end
+ nodes.compact!
+ when %r!^~!
+ last = expr = $'
+ nodes.map! do |node|
+ siblings = node.parent.children
+ siblings[(siblings.index(node)+1)..-1]
+ end
+ nodes.flatten!
+ when %r!^[|,]!
+ last = expr = " #$'"
+ nodes.shift if nodes.first == self
+ done += nodes
+ nodes = [self]
+ else
+ m = expr.match(%r!^([#.]?)([a-z0-9\\*_-]*)!i).to_a
+ after = $'
+ mt = after[%r!:[a-z0-9\\*_-]+!i, 0]
+ oop = false
+ if mt and not (mt == ":not" or Traverse.method_defined? "filter[#{mt}]")
+ after = $'
+ m[2] += mt
+ expr = after
+ end
+ if m[1] == '#'
+ oid = get_element_by_id(m[2])
+ nodes = oid ? [oid] : []
+ expr = after
+ else
+ m[2] = "*" if after =~ /^\(\)/ || m[2] == "" || m[1] == "."
+ ret = []
+ nodes.each do |node|
+ case m[2]
+ when '*'
+ node.traverse_element { |n| ret << n }
+ else
+ if node.respond_to? :get_elements_by_tag_name
+ ret += [*node.get_elements_by_tag_name(m[2])] - [*(node unless last)]
+ end
+ end
+ end
+ nodes = ret
+ end
+ last = nil
+ end
+
+ hist << expr
+ break if hist[-1] == hist[-2]
+ nodes, expr = Elements.filter(nodes, expr)
+ end
+ nodes = done + nodes.flatten.uniq
+ if blk
+ nodes.each(&blk)
+ self
+ else
+ Elements[*nodes]
+ end
+ end
+ alias_method :/, :search
+
+ # Find the first matching node for the CSS or XPath
+ # +expr+ string.
+ def at(expr)
+ search(expr).first
+ end
+ alias_method :%, :at
+
+ # +traverse_element+ traverses elements in the tree.
+ # It yields elements in depth first order.
+ #
+ # If _names_ are empty, it yields all elements.
+ # If non-empty _names_ are given, it should be list of universal names.
+ #
+ # A nested element is yielded in depth first order as follows.
+ #
+ # t = Hpricot('')
+ # t.traverse_element("a", "c") {|e| p e}
+ # # =>
+ # {elem {elem {emptyelem } } {emptyelem } }
+ # {emptyelem }
+ # {emptyelem }
+ #
+ # Universal names are specified as follows.
+ #
+ # t = Hpricot(<<'End')
+ #
+ #
+ #
+ #
+ # End
+ # t.traverse_element("{http://www.w3.org/1999/xhtml}meta") {|e| p e}
+ # # =>
+ # {emptyelem <{http://www.w3.org/1999/xhtml}meta name="robots" content="index,nofollow">}
+ # {emptyelem <{http://www.w3.org/1999/xhtml}meta name="author" content="Who am I?">}
+ #
+ def traverse_element(*names, &block) # :yields: element
+ if names.empty?
+ traverse_all_element(&block)
+ else
+ name_set = {}
+ names.each {|n| name_set[n] = true }
+ traverse_some_element(name_set, &block)
+ end
+ nil
+ end
+
+ # Find children of a given +tag_name+.
+ #
+ # ele.children_of_type('p')
+ # #=> [...array of paragraphs...]
+ #
+ def children_of_type(tag_name)
+ if respond_to? :children
+ children.find_all do |x|
+ x.respond_to?(:pathname) && x.pathname == tag_name
+ end
+ end
+ end
+
+ end
+
+ module Container::Trav
+ # Return all children of this node which can contain other
+ # nodes. This is a good way to get all HTML elements which
+ # aren't text, comment, doctype or processing instruction nodes.
+ def containers
+ children.grep(Container::Trav)
+ end
+
+ # Returns the container node neighboring this node to the south: just below it.
+ # By "container" node, I mean: this method does not find text nodes or comments or cdata or any of that.
+ # See Hpricot::Traverse#next_node if you need to hunt out all kinds of nodes.
+ def next_sibling
+ sib = parent.containers
+ sib[sib.index(self) + 1] if parent
+ end
+
+ # Returns the container node neighboring this node to the north: just above it.
+ # By "container" node, I mean: this method does not find text nodes or comments or cdata or any of that.
+ # See Hpricot::Traverse#previous_node if you need to hunt out all kinds of nodes.
+ def previous_sibling
+ sib = parent.containers
+ x = sib.index(self) - 1
+ sib[x] if sib and x >= 0
+ end
+
+ # Find all preceding sibling elements. Like the other "sibling" methods, this weeds
+ # out text and comment nodes.
+ def preceding_siblings()
+ sibs = parent.containers
+ si = sibs.index(self)
+ return Elements[*sibs[0...si]]
+ end
+
+ # Find sibling elements which follow the current one. Like the other "sibling" methods, this weeds
+ # out text and comment nodes.
+ def following_siblings()
+ sibs = parent.containers
+ si = sibs.index(self) + 1
+ return Elements[*sibs[si...sibs.length]]
+ end
+
+ # Puts together an array of neighboring sibling elements based on their proximity
+ # to this element.
+ #
+ # This method accepts ranges and sets of numbers.
+ #
+ # ele.siblings_at(-3..-1, 1..3) # gets three elements before and three after
+ # ele.siblings_at(1, 5, 7) # gets three elements at offsets below the current element
+ # ele.siblings_at(0, 5..6) # the current element and two others
+ #
+ # Like the other "sibling" methods, this doesn't find text and comment nodes.
+ # Use nodes_at to include those nodes.
+ def siblings_at(*pos)
+ sib = parent.containers
+ i, si = 0, sib.index(self)
+ Elements[*
+ sib.select do |x|
+ sel = case i - si when *pos
+ true
+ end
+ i += 1
+ sel
+ end
+ ]
+ end
+
+ # Replace +old+, a child of the current node, with +new+ node.
+ def replace_child(old, new)
+ reparent new
+ children[children.index(old), 1] = [*new]
+ end
+
+ # Insert +nodes+, an array of HTML elements or a single element,
+ # before the node +ele+, a child of the current node.
+ def insert_before(nodes, ele)
+ case nodes
+ when Array
+ nodes.each { |n| insert_before(n, ele) }
+ else
+ reparent nodes
+ children[children.index(ele) || 0, 0] = nodes
+ end
+ end
+
+ # Insert +nodes+, an array of HTML elements or a single element,
+ # after the node +ele+, a child of the current node.
+ def insert_after(nodes, ele)
+ case nodes
+ when Array
+ nodes.reverse_each { |n| insert_after(n, ele) }
+ else
+ reparent nodes
+ idx = children.index(ele)
+ children[idx ? idx + 1 : children.length, 0] = nodes
+ end
+ end
+
+ # +each_child+ iterates over each child.
+ def each_child(&block) # :yields: child_node
+ children.each(&block)
+ nil
+ end
+
+ # +each_child_with_index+ iterates over each child.
+ def each_child_with_index(&block) # :yields: child_node, index
+ children.each_with_index(&block)
+ nil
+ end
+
+ # +find_element+ searches an element which universal name is specified by
+ # the arguments.
+ # It returns nil if not found.
+ def find_element(*names)
+ traverse_element(*names) {|e| return e }
+ nil
+ end
+
+ # Returns a list of CSS classes to which this element belongs.
+ def classes
+ get_attribute('class').to_s.strip.split(/\s+/)
+ end
+
+ def get_element_by_id(id)
+ traverse_all_element do |ele|
+ if ele.elem? and eid = ele.get_attribute('id')
+ return ele if eid.to_s == id
+ end
+ end
+ nil
+ end
+
+ def get_elements_by_tag_name(*a)
+ list = Elements[]
+ traverse_element(*a.map { |tag| [tag, "{http://www.w3.org/1999/xhtml}#{tag}"] }.flatten) do |e|
+ list << e
+ end
+ list
+ end
+
+ def each_hyperlink_attribute
+ traverse_element(
+ '{http://www.w3.org/1999/xhtml}a',
+ '{http://www.w3.org/1999/xhtml}area',
+ '{http://www.w3.org/1999/xhtml}link',
+ '{http://www.w3.org/1999/xhtml}img',
+ '{http://www.w3.org/1999/xhtml}object',
+ '{http://www.w3.org/1999/xhtml}q',
+ '{http://www.w3.org/1999/xhtml}blockquote',
+ '{http://www.w3.org/1999/xhtml}ins',
+ '{http://www.w3.org/1999/xhtml}del',
+ '{http://www.w3.org/1999/xhtml}form',
+ '{http://www.w3.org/1999/xhtml}input',
+ '{http://www.w3.org/1999/xhtml}head',
+ '{http://www.w3.org/1999/xhtml}base',
+ '{http://www.w3.org/1999/xhtml}script') {|elem|
+ case elem.name
+ when %r{\{http://www.w3.org/1999/xhtml\}(?:base|a|area|link)\z}i
+ attrs = ['href']
+ when %r{\{http://www.w3.org/1999/xhtml\}(?:img)\z}i
+ attrs = ['src', 'longdesc', 'usemap']
+ when %r{\{http://www.w3.org/1999/xhtml\}(?:object)\z}i
+ attrs = ['classid', 'codebase', 'data', 'usemap']
+ when %r{\{http://www.w3.org/1999/xhtml\}(?:q|blockquote|ins|del)\z}i
+ attrs = ['cite']
+ when %r{\{http://www.w3.org/1999/xhtml\}(?:form)\z}i
+ attrs = ['action']
+ when %r{\{http://www.w3.org/1999/xhtml\}(?:input)\z}i
+ attrs = ['src', 'usemap']
+ when %r{\{http://www.w3.org/1999/xhtml\}(?:head)\z}i
+ attrs = ['profile']
+ when %r{\{http://www.w3.org/1999/xhtml\}(?:script)\z}i
+ attrs = ['src', 'for']
+ end
+ attrs.each {|attr|
+ if hyperlink = elem.get_attribute(attr)
+ yield elem, attr, hyperlink
+ end
+ }
+ }
+ end
+ private :each_hyperlink_attribute
+
+ # +each_hyperlink_uri+ traverses hyperlinks such as HTML href attribute
+ # of A element.
+ #
+ # It yields Hpricot::Text and URI for each hyperlink.
+ #
+ # The URI objects are created with a base URI which is given by
+ # HTML BASE element or the argument ((|base_uri|)).
+ # +each_hyperlink_uri+ doesn't yields href of the BASE element.
+ def each_hyperlink_uri(base_uri=nil) # :yields: hyperlink, uri
+ base_uri = URI.parse(base_uri) if String === base_uri
+ links = []
+ each_hyperlink_attribute {|elem, attr, hyperlink|
+ if %r{\{http://www.w3.org/1999/xhtml\}(?:base)\z}i =~ elem.name
+ base_uri = URI.parse(hyperlink.to_s)
+ else
+ links << hyperlink
+ end
+ }
+ if base_uri
+ links.each {|hyperlink| yield hyperlink, base_uri + hyperlink.to_s }
+ else
+ links.each {|hyperlink| yield hyperlink, URI.parse(hyperlink.to_s) }
+ end
+ end
+
+ # +each_hyperlink+ traverses hyperlinks such as HTML href attribute
+ # of A element.
+ #
+ # It yields Hpricot::Text.
+ #
+ # Note that +each_hyperlink+ yields HTML href attribute of BASE element.
+ def each_hyperlink # :yields: text
+ links = []
+ each_hyperlink_attribute {|elem, attr, hyperlink|
+ yield hyperlink
+ }
+ end
+
+ # +each_uri+ traverses hyperlinks such as HTML href attribute
+ # of A element.
+ #
+ # It yields URI for each hyperlink.
+ #
+ # The URI objects are created with a base URI which is given by
+ # HTML BASE element or the argument ((|base_uri|)).
+ def each_uri(base_uri=nil) # :yields: URI
+ each_hyperlink_uri(base_uri) {|hyperlink, uri| yield uri }
+ end
+ end
+
+ # :stopdoc:
+ module Doc::Trav
+ def traverse_all_element(&block)
+ children.each {|c| c.traverse_all_element(&block) }
+ end
+ def xpath
+ "/"
+ end
+ def css_path
+ nil
+ end
+ end
+
+ module Elem::Trav
+ def traverse_all_element(&block)
+ yield self
+ children.each {|c| c.traverse_all_element(&block) }
+ end
+ end
+
+ module Leaf::Trav
+ def traverse_all_element
+ yield self
+ end
+ end
+
+ module Doc::Trav
+ def traverse_some_element(name_set, &block)
+ children.each {|c| c.traverse_some_element(name_set, &block) }
+ end
+ end
+
+ module Elem::Trav
+ def traverse_some_element(name_set, &block)
+ yield self if name_set.include? self.name
+ children.each {|c| c.traverse_some_element(name_set, &block) }
+ end
+ end
+
+ module Leaf::Trav
+ def traverse_some_element(name_set)
+ end
+ end
+ # :startdoc:
+
+ module Traverse
+ # +traverse_text+ traverses texts in the tree
+ def traverse_text(&block) # :yields: text
+ traverse_text_internal(&block)
+ nil
+ end
+ end
+
+ # :stopdoc:
+ module Container::Trav
+ def traverse_text_internal(&block)
+ each_child {|c| c.traverse_text_internal(&block) }
+ end
+ end
+
+ module Leaf::Trav
+ def traverse_text_internal
+ end
+ end
+
+ module Text::Trav
+ def traverse_text_internal
+ yield self
+ end
+ end
+ # :startdoc:
+
+ module Container::Trav
+ # +filter+ rebuilds the tree without some components.
+ #
+ # node.filter {|descendant_node| predicate } -> node
+ # loc.filter {|descendant_loc| predicate } -> node
+ #
+ # +filter+ yields each node except top node.
+ # If given block returns false, corresponding node is dropped.
+ # If given block returns true, corresponding node is retained and
+ # inner nodes are examined.
+ #
+ # +filter+ returns an node.
+ # It doesn't return location object even if self is location object.
+ #
+ def filter(&block)
+ subst = {}
+ each_child_with_index {|descendant, i|
+ if yield descendant
+ if descendant.elem?
+ subst[i] = descendant.filter(&block)
+ else
+ subst[i] = descendant
+ end
+ else
+ subst[i] = nil
+ end
+ }
+ to_node.subst_subnode(subst)
+ end
+ end
+
+ module Doc::Trav
+ # +title+ searches title and return it as a text.
+ # It returns nil if not found.
+ #
+ # +title+ searchs following information.
+ #
+ # - ... in HTML
+ # - ... in RSS
+ def title
+ e = find_element('title',
+ '{http://www.w3.org/1999/xhtml}title',
+ '{http://purl.org/rss/1.0/}title',
+ '{http://my.netscape.com/rdf/simple/0.9/}title')
+ e && e.extract_text
+ end
+
+ # +author+ searches author and return it as a text.
+ # It returns nil if not found.
+ #
+ # +author+ searchs following information.
+ #
+ # - in HTML
+ # - in HTML
+ # - author-name in RSS
+ # - author-name in RSS
+ def author
+ traverse_element('meta',
+ '{http://www.w3.org/1999/xhtml}meta') {|e|
+ begin
+ next unless e.fetch_attr('name').downcase == 'author'
+ author = e.fetch_attribute('content').strip
+ return author if !author.empty?
+ rescue IndexError
+ end
+ }
+
+ traverse_element('link',
+ '{http://www.w3.org/1999/xhtml}link') {|e|
+ begin
+ next unless e.fetch_attr('rev').downcase == 'made'
+ author = e.fetch_attribute('title').strip
+ return author if !author.empty?
+ rescue IndexError
+ end
+ }
+
+ if channel = find_element('{http://purl.org/rss/1.0/}channel')
+ channel.traverse_element('{http://purl.org/dc/elements/1.1/}creator') {|e|
+ begin
+ author = e.extract_text.strip
+ return author if !author.empty?
+ rescue IndexError
+ end
+ }
+ channel.traverse_element('{http://purl.org/dc/elements/1.1/}publisher') {|e|
+ begin
+ author = e.extract_text.strip
+ return author if !author.empty?
+ rescue IndexError
+ end
+ }
+ end
+
+ nil
+ end
+
+ end
+
+ module Doc::Trav
+ def root
+ es = []
+ children.each {|c| es << c if c.elem? }
+ raise Hpricot::Error, "no element" if es.empty?
+ raise Hpricot::Error, "multiple top elements" if 1 < es.length
+ es[0]
+ end
+ end
+
+ module Elem::Trav
+ def has_attribute?(name)
+ self.raw_attributes && self.raw_attributes.has_key?(name.to_s)
+ end
+ def get_attribute(name)
+ a = self.raw_attributes && self.raw_attributes[name.to_s]
+ a = Hpricot.uxs(a) if a
+ a
+ end
+ alias_method :[], :get_attribute
+ def set_attribute(name, val)
+ altered!
+ self.raw_attributes ||= {}
+ self.raw_attributes[name.to_s] = Hpricot.xs(val)
+ end
+ alias_method :[]=, :set_attribute
+ def remove_attribute(name)
+ name = name.to_s
+ if has_attribute? name
+ altered!
+ self.raw_attributes.delete(name)
+ end
+ end
+ end
+
+end
diff --git a/vendor/gems/hpricot-0.6/lib/hpricot/xchar.rb b/vendor/gems/hpricot-0.6/lib/hpricot/xchar.rb
new file mode 100644
index 0000000..6a5aa4b
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/lib/hpricot/xchar.rb
@@ -0,0 +1,94 @@
+#!/usr/bin/env ruby
+
+# The XChar library is provided courtesy of Sam Ruby (See
+# http://intertwingly.net/stories/2005/09/28/xchar.rb)
+
+# --------------------------------------------------------------------
+
+######################################################################
+module Hpricot
+
+ ####################################################################
+ # XML Character converter, from Sam Ruby:
+ # (see http://intertwingly.net/stories/2005/09/28/xchar.rb).
+ #
+ module XChar # :nodoc:
+
+ # See
+ # http://intertwingly.net/stories/2004/04/14/i18n.html#CleaningWindows
+ # for details.
+ CP1252 = { # :nodoc:
+ 128 => 8364, # euro sign
+ 130 => 8218, # single low-9 quotation mark
+ 131 => 402, # latin small letter f with hook
+ 132 => 8222, # double low-9 quotation mark
+ 133 => 8230, # horizontal ellipsis
+ 134 => 8224, # dagger
+ 135 => 8225, # double dagger
+ 136 => 710, # modifier letter circumflex accent
+ 137 => 8240, # per mille sign
+ 138 => 352, # latin capital letter s with caron
+ 139 => 8249, # single left-pointing angle quotation mark
+ 140 => 338, # latin capital ligature oe
+ 142 => 381, # latin capital letter z with caron
+ 145 => 8216, # left single quotation mark
+ 146 => 8217, # right single quotation mark
+ 147 => 8220, # left double quotation mark
+ 148 => 8221, # right double quotation mark
+ 149 => 8226, # bullet
+ 150 => 8211, # en dash
+ 151 => 8212, # em dash
+ 152 => 732, # small tilde
+ 153 => 8482, # trade mark sign
+ 154 => 353, # latin small letter s with caron
+ 155 => 8250, # single right-pointing angle quotation mark
+ 156 => 339, # latin small ligature oe
+ 158 => 382, # latin small letter z with caron
+ 159 => 376, # latin capital letter y with diaeresis
+ }
+
+ # See http://www.w3.org/TR/REC-xml/#dt-chardata for details.
+ PREDEFINED = {
+ 34 => '"', # quotation mark
+ 38 => '&', # ampersand
+ 60 => '<', # left angle bracket
+ 62 => '>' # right angle bracket
+ }
+ PREDEFINED_U = PREDEFINED.inject({}) { |hsh, (k, v)| hsh[v] = k; hsh }
+
+ # See http://www.w3.org/TR/REC-xml/#charsets for details.
+ VALID = [
+ 0x9, 0xA, 0xD,
+ (0x20..0xD7FF),
+ (0xE000..0xFFFD),
+ (0x10000..0x10FFFF)
+ ]
+ end
+
+ class << self
+ # XML escaped version of chr
+ def xchr(str)
+ n = XChar::CP1252[str] || str
+ case n when *XChar::VALID
+ XChar::PREDEFINED[n] or (n<128 ? n.chr : "#{n};")
+ else
+ '*'
+ end
+ end
+
+ # XML escaped version of to_s
+ def xs(str)
+ str.to_s.unpack('U*').map {|n| xchr(n)}.join # ASCII, UTF-8
+ rescue
+ str.to_s.unpack('C*').map {|n| xchr(n)}.join # ISO-8859-1, WIN-1252
+ end
+
+ # XML unescape
+ def uxs(str)
+ str.to_s.
+ gsub(/\&\w+;/) { |x| (XChar::PREDEFINED_U[x] || ??).chr }.
+ gsub(/\&\#(\d+);/) { [$1.to_i].pack("U*") }
+ end
+ end
+end
+
diff --git a/vendor/gems/hpricot-0.6/test/files/basic.xhtml b/vendor/gems/hpricot-0.6/test/files/basic.xhtml
new file mode 100644
index 0000000..898f0ea
--- /dev/null
+++ b/vendor/gems/hpricot-0.6/test/files/basic.xhtml
@@ -0,0 +1,17 @@
+
+
+
+
+ Sample XHTML
+
+
+
+
+
+
+ James Patrick Kelly and John Kessel gave a great interview to Sci Fi Weekly about their new anthology, Feeling Very Strange: The Slipstream Anthology. The book has a top-notch table-of-contents, stories that defy genre conventions and make your head spin in a good way.
+
+
+
+We make the point in our introduction that slipstream isn't really a genre at the moment and may never be one. What it is, in our opinion, is a literary effect--in the same way that horror or comedy are literary effects achieved by many different kinds of dissimilar stories. What is that effect? We borrowed the term cognitive dissonance from the psychologists. When we are presented with two contradictory cognitions--impressions, feelings, beliefs--we experience cognitive dissonance, a kind of psychic discomfort that we normally try to ease by discounting one of the cognitions as false or illusory and promoting the other to reality. But in some cases we aren't well served by this convenient sorting out.
+
+We think that what slipstream stories do is to embrace cognitive dissonance. F. Scott Fitzgerald once said that "The test of a first-rate intelligence is the ability to hold two opposing ideas in mind at the same time and still retain the ability to function." We believe that such an ability is necessary to cope with life in the 21st century and that stories that ask us to exercise that ability are an expression of the zeitgeist. Do you really need a definitive answer as to whether an electron is a wave or a particle? Why? Maybe it's time to make room for uncertainty in contemporary fiction, even if the stories do make you feel very strange. Slipstream may use metafictional techniques to estrange us from consensus reality, they may rewrite history, they may mash up different styles or genres. But that's the point, as we see it. Slipstream has no rules, it has only results.
+
+
+
+ College kids reportedly taking more smart drugs
+
+ High-achieving college kids are reportedly dipping into "brain-steroids" -- drugs like Ritalin and Provigil, which focus attention. No one really knows how widespread this practice is, since it's uncommon for anyone to get busted for peddling smart drugs, and the side-effects of "abuse" are minimal.
+
+This strikes me as the canonical cognitive liberty fight: why shouldn't you be allowed to make an informed decision about what state of mind you'd like to be in? Why will the law allow people to kill brain and liver cells with stupefying booze, but not smart drugs?
+
+
+"What was a surprise, though, was the alarming rate of senior business majors who have used" the drugs, he writes. Almost 90 percent reported at least occasional use of "smart pills" at crunch times such as final exams, including Adderall, Ritalin, Strattera and others. Of those, three-quarters did not have a legitimate prescription, obtaining the pills from friends. "We were shocked," Salantrie writes. He says that in his report, he was "attempting to bring to light the secondary market for Adderall" specifically because "most of the university is not aware" of its extent, he says.
+
+
+
+The next Worth1000 photoshopping contest challenges artists to fake UFO-sightings photos. The quality of entries here is a little uneven, but the best of the lot are real gems.
+
+Link
+
+
+
+
+
+ Rube Goldberg machine built out of sticks and stones
+
+
+
+There's a feature on today's Make video podcast about a giant, elaborate Rube Goldberg machine assembled out of sticks and stones in a forest. The video features some jaw-dropping, Mousetrap-style action, and the use of found forest-floor materials makes it all the more Wile E Coyote. The video features tips on setting up your own woodsy contraption.
+
+
+Link
+
+
+
+
+
+ Lampooning the American dismissal of Gitmo suicides
+
+ Fafblog today features a scathing, brilliant satirical look at the US characterization of the Guantanamo Bay suicides as an attack on America. Fafblog is consistently the best political satire/commentary on the net, the Web equivalent of Jon Stewart and Stephen Colbert, and they're finally back after a too-long hiatus. The characterization of the Gitmo suicides as an act of terrorism is so ugly and disingenuous that it begged to be punctured. I'm thankful that Fafblog is back to perform that service.
+
+
+
+Run for your lives - America is under attack! Just days ago three prisoners at Guantanamo Bay committed suicide in a savage assault on America's freedom to not care about prisoner suicides! Oh sure, the "Blame Atrocities First" crowd will tell you these prisoners were "driven to despair," that they "had no rights," that they were "held and tortured without due process or judicial oversight in a nightmarish mockery of justice." But what they won't tell you is that they only committed suicide as part of a diabolical ruse to trick the world into thinking our secret torture camp is the kind of secret torture camp that drives its prisoners to commit suicide! This fiendish attempt to slander the great American institution of the gulag is nothing less than an act of asymmetrical warfare against the United States - a noose is just a suicide bomb with a very small blast radius, people! - and when faced with a terrorist attack, America must respond. Giblets demands immediate retaliatory airstrikes on depressed Muslim torture victims throughout the mideast!
+
+"Oh but Giblets there are dozens of innocent prisoners in Guantanamo" you say because you are a namby-pamby appeasenik who suckles at the teat of terror. Well if these Guantanamo prisoners are so innocent then what are they doing in Guantanamo? Sneaking into our secret military prisons as part of an elaborate plot to make it look like we're holding them in our secret military prisons, that's what! And once they get there they can chain themselves to the floor, break their bones on helpless guards' fists, and waterboard themselves to their heart's content to further their sinister Salafi scheme to sully the reputation of secret American torture facilities everywhere!
+
+
+ A new Neil Gaiman tribute CD is coming out in July. One of the tracks is already available -- "Mr Punch" by Future Bible Heroes, and it's a delight. Apparently, Stephin Merritt (from Future Bible Heroes) is also doing a Lemony Snickett-inspired CD in October.
+
+
+
+Track Listing:
+1 Rasputina - Coraline
+2 ThouShaltNot - When Everyone Forgets
+3 Tapping The Vein - Trader Boy
+4 Lunascape - Raven Star
+5 Deine Lakaien - A Fish Called Prince
+6 Thea Gilmore - Even Gods Do
+7 Rose Berlin (feat. Curve) - Coraline
+8 Schandmaul - Magda Treadgolds Märchen
+9 Hungry Lucy - We Won't Go
+10 Voltaire w/The Oddz - Come Sweet Death
+11 Future Bible Heroes - Mr. Punch
+12 Razed in Black - The Endless
+13 The Cruxshadows - Wake the White Queen
+14 Ego Likeness - You Better Leave the Stars Alone
+15 Azam Ali - The Cold Black Key
+16 Joachim Witt - Vandemar
+17 Tori Amos - Sister Named Desire (New Master)
+
+
+
+
+Tom spotted this DC license plate, reading BLK DRM. He thinks it's an anti-DRM lobbyist's plate, which is plausible, though with the acronym soup in Washington, it could stand for just about anything.
+
+Link
+
+(Thanks, Tom)
+
+
+
+
+
+
+
+ClothUK makes easy chairs and other soft furnishings upholstered with fabric that's printed with the lush, oversized photo of your choice. Not cheap, tho!
+
+Link
+
+(via Wonderland)
+
+
+
+
+
+
+
+EFF has just launched a new video: The Corruptibles -- the story of Copyright Supervillains who patrol the Broadcast Flag future, blowing up our free and open devices. It's a great, funny viral short, and well worth a watch.
+
+
+
+Link
+
+
+
+
+
+ WIPO meets to screw up podcasting, Barcelona, June 21
+
+ The United Nations' World Intellectual Property Organization has called a last-minute meeting on June 21 in Barcelona, out of the normal diplomatic venues to try to ram through the Broadcasting Treaty. This treaty gives broadcasters (not creators or copyright holders) the right to tie up the use of audiovisual material for 50 years after broadcasting it, even if the programs are in the public domain, Creative Commons licensed, or not copyrightable.
+
+The Barcelona meeting brings together lots of latinamerican broadcasters -- who no doubt love the idea of a new monopoly right that they get for free merely for broadcasting a work. Bringing these casters in is a way of undermining the effective opposition to the treaty that's come from countries like Brazil and Chile.
+
+No public interest groups are on the bill to give a counterpoint (of course not -- WIPO is the kind of place where public interest groups' handouts are thrown in the toilets' trashcans).
+
+This meeting is especially deadly, because it looks like they're trying to sneak podcasting back into the treaty, after agreeing to take it out at the last big meeting in Geneva.
+
+The good news is, it's open to the public. If you're a digital rights activist in Barcelona -- or just someone who cares about how big corporations are taking away your rights to use works freely -- then you need to be at this meeting.
+
+
+Webcasting will clearly be part of next week's discussions. That much is clear from the title of next week's event: "From the Rome Convention to Podcasting". One of the invited speakers is from Yahoo! Europe, one of the proponents of new rights for webcasters. This, despite the fact that webcasting and simulcasting were taken out of the "traditional" Broadcasting Treaty and put on the slow track last month in response to concerns expressed by the majority of WIPO member states.
+
+The good news: unlike earlier meetings, this one is open to the public, with prior registration requested. So if you care about the proposed treaties and can get to the Barcelona meeting, this is your opportunity to stand up and be counted for the public interest.
+
+If you’re in the U.S., please tell your Congressional representatives to hold hearings on the proposed treaties before it’s too late. And if you need a reminder about the harm that these treaties could wreak on access to knowledge and technological innovation, read Jamie Boyle’s piece in today’s Financial Times.
+
+
+ I came across this funny list of "Things to Do," written by "fifth Boing Boinger" Stefan Jones, which was published on the pre-blog version of boingboing.net.
+
+
1. Get $25 worth of paper currency from one of those countries where $25 worth of currency fills up two wheel barrows. Divide it into five lots and send them, along with an incomprehensible letter, to the addresses listed in an email chain letter.
+
+
2. Build some gigantic rat traps, with wooden bases at least 2' x 3' and baited with an entire blocks of government cheese. Plant the traps, in sprung state, near a local chemical company. Wear giant rat foot shoes while doing this.
+
+
3. Get a supply of those little plastic ties used to seal hotel minibars after they are loaded with a full complement of overpriced goodies. Bring them and a supply of useful things (socks, condoms, aspirin) and strange things (McGruff the Crime Dog coloring books, bottles of Moxie, a can of Hormel Calf Brains in Milk Gravy) while travelling. Put the things in the minibar before sealing it up.
+
+Here's a video of two adorable, autonomous "sexed robots."
+
+
+The sexed robots are autonomous wheeled platforms fitted with nylon genital organs, respectively male and female. They are programmed to explore their environment, occasionally entering a "in heat" mode, where they will try and locate a partner in the same state. If a partner is located, the robots will attempt to mate.
+ Burroughs' Encyclopaedia of Astounding Facts and Useful Information, 1889
+
+ Manybooks.net, which converts Project Gutenberg titles into useful formats for reading on Palm devics, iPods, and ebook readers, recently made available a fantastic compendium called Burroughs' Encyclopaedia of Astounding Facts and Useful Information, 1889: Universal Assistant and Treasure-House of Information to be Consulted on Every Question That Arises in Everyday Life by Young and Old Alike!.
+
+
It's an amazing combination of a proto-Ripley's, a cookbook, etiquette guide, and almanac.
+
+
+
+
+WONDERS OF MINUTE WORKMANSHIP.
+
+
In the twentieth year of Queen Elizabeth, a blacksmith named Mark Scaliot, made a lock consisting of eleven pieces of iron, steel and brass, all which, together with a key to it, weighed but one grain of gold. He also made a chain of gold, consisting of forty-three links, and, having fastened this to the before-mentioned lock and key, he put the chain about the neck of a flea, which drew them all with ease. All these together, lock and key, chain and flea, weighed only one grain and a half.
+
+
Oswaldus Norhingerus, who was more famous even than Scaliot for his minute contrivances, is said to have made 1,600 dishes of turned ivory, all perfect and complete in every part, yet so small, thin and slender, that all of them were included at once in a cup turned out of a pepper-corn of the common size. Johannes Shad, of Mitelbrach, carried this wonderful work with him to Rome, and showed it to Pope Paul V., who saw and counted them all by the help of a pair of spectacles. They were so little as to be almost invisible to the eye.
+
+
Johannes Ferrarius, a Jesuit, had in his posession cannons of wood, with their carriages, wheels, and all other military furniture, all of which were also contained in a pepper-corn of the ordinary size.
+ AOL's efforts to keep you from quitting your account
+
+ Listen to this recording of a guy who called AOL to try to cancel his account and the AOL jerk who tries to keep him from canceling. Just disgusting. Link(via Digg)
+
+
+
+ LA's South Central Farm under police siege right now
+
+ The police have closed on South Central Farm, the largest community garden in the USA. The farms were planted after the Rodney King uprising, when the land was given to the neighborhood, and it has been reclaimed and cultivated by 350 families. The city reneged on its promise and sold the land to a developer, who has now moved on it with bulldozers and a riot squad.
+
+
+The South Central Farm is currently under attack. An early morning raid began this 5-hour long eviction that is still in process. Trees are being cut down, bulldozers are leveling the families’ food, hundreds of protesters are on site rallying with tears in their eyes as the nation’s largest urban farm is destroyed before them. The L.A.P.D. is on tactical alert as fire ladders and cherry pickers are being brought in to remove the tree-sitters. The 350 families created this oasis 14 years ago in the wake of the 1992 uprising when this land was offered to the community by the then Mayor as a form of mitigation.
+
+Update: Elan sez, "the land for the farm was originally taken from Ralph Horowitz through eminent domain with the intension of using it for a trash incinerator. When the incinerator fell through, the city was required to sell it back to the Horowitz (after a ten year period of first refusal)."
+
+
+
+ iPod dock/speakers built into bumwad dispenser
+
+
+
+This iPod dock and speakers built into a bumwad dispenser isn't as weird as it seems at first blush -- lots of us have a radio in the bathroom; this is a way of listening to your iPod without sacrificing your limited counterspace to an electronics footprint.
+
+Link
+
+(via Popgadget)
+
+
+
+
+
+ Cory's Someone to Town shortlisted for Canada's sf book award
+
+
+I'm pleased as punch to say that my novel, Someone Comes to Town, Someone Leave Town has been shortlisted for the Sunburst, Canada's national science fiction award. The Sunburst jury honored me with the award in 2004 for my short story collection A Place So Foreign and Eight More and this is a double-helping of delight.
+
+ A new study suggests that people may think that the happiest days of their lives are when they're young, but that belief doesn't jibe with reality. University of Michigan and VA Ann Arbor healthcare Systems researchers polled 540 adults in the 21-40 age group and 60+ age group. They rated their own happiness right now, predicted how happy they'd be in the future, and also how happy they think others are in those age groups. The results were published in the Journal of Happiness Studies, which is a delightful name for a scientific publication. From the University of Michigan Health System:
+
"Overall, people got it wrong, believing that most people become less happy as they age, when in fact this study and others have shown that people tend to become happier over time," says lead author Heather Lacey, Ph.D., a VA postdoctoral fellow and member of the U-M Medical School's Center for Behavioral and Decision Sciences in Medicine. "Not only do younger people believe that older people are less happy, but older people believe they and others must have been happier 'back then'. Neither belief is accurate..."
+
+"People often believe that happiness is a matter of circumstance, that if something good happens, they will experience long-lasting happiness, or if something bad happens, they will experience long-term misery," (says co-author Peter Ubel). "But instead, people's happiness results more from their underlying emotional resources -- resources that appear to grow with age. People get better at managing life's ups and downs, and the result is that as they age, they become happier -- even though their objective circumstances, such as their health, decline."
+
+
+Here's a video clip of a male Australian lyrebird, which sings complex songs to attract mates. Lyrebirds' songs are composed of sounds they hear, including sounds from machines, such as a camera's shutter mechanism and film drive, a car alarm, and logging equipment. This bird is like a tape recorder. Link(thanks, Coop!)
+
+
+
+ The Aymara, an indigenous group in the Andes highlands, have a concept of time that's opposite our own spatial metaphor. A new study by cognitive scientists explains how the Aymara consider the past to be ahead and the future behind them. According to the study, this is the first documented culture that seems not to have mapped time with the properties of space "as if (the future) were in front of ego and the past in back." From UCSD:
+
The linguistic evidence seems, on the surface, clear: The Aymara language recruits “nayra,†the basic word for “eye,†“front†or “sight,†to mean “past†and recruits “qhipa,†the basic word for “back†or “behind,†to mean “future.†So, for example, the expression “nayra mara†– which translates in meaning to “last year†– can be literally glossed as “front year..."
The Aymara, especially the elderly who didn’t command a grammatically correct Spanish, indicated space behind themselves when speaking of the future – by thumbing or waving over their shoulders – and indicated space in front of themselves when speaking of the past – by sweeping forward with their hands and arms, close to their bodies for now or the near past and farther out, to the full extent of the arm, for ancient times. In other words, they used gestures identical to the familiar ones – only exactly in reverse.
+
+“These findings suggest that cognition of such everyday abstractions as time is at least partly a cultural phenomenon,†(University of California, San Diego professor Rafael) Nunez said. “That we construe time on a front-back axis, treating future and past as though they were locations ahead and behind, is strongly influenced by the way we move, by our dorsoventral morphology, by our frontal binocular vision, etc. Ultimately, had we been blob-ish amoeba-like creatures, we wouldn’t have had the means to create and bring forth these concepts.
+
+“But the Aymara counter-example makes plain that there is room for cultural variation. With the same bodies – the same neuroanatomy, neurotransmitters and all – here we have a basic concept that is utterly different,†he said.
+
Prince performed an acoustic number at last night's Webby Awards in NYC. Prince won a Lifetime Achievement Award. His five word acceptance speech: "Everything you think is true." Also in attendance were Robert Kahn, Gorillaz, Arianna Huffington, and dozens of other interesting folks. Rob Corddry hosted. Congrats to all the winners and our friends at the Webby Awards for what sounds like an amazing ceremony! Check Rocketboom for the edit of the evening. Link
+
+
+
+ Toronto Hydro, the electrical authority in Toronto, has spent decades building electrical substations that are disguised as typical family houses:
+
+
+
+In 1987, Canadian photographer Robin Collyer began documenting houses that aren't houses at all – they're architecturally-disguised electrical substations, complete with windows, blinds, and bourgeois landscaping.
+
+"During the 1950s and 1960s," Collyer explains in a recent issue of Cabinet Magazine, "the Hydro-Electric public utilities in the metropolitan region of Toronto built structures known as 'Bungalow-Style Substations.' These stations, which have transforming and switching functions, were constructed in a manner that mimics the style and character of the different neighborhoods."
+
+
+
+
+Peggy Dembicer cloned a 1978 Candyland game-board using over 100,000 novelty beads. She's documented the finished project on Flickr, with details of some of the finer work.
+
+Link
+
+(via Make Blog)
+
+
+
+
+
+ Stanford prof sues James Joyce estate for right to study Joyce
+
+ A prof at Stanford University is suing the estate of James Joyce over the estate's long practice of destroying documents vital to Joyce scholarship, and of intimidating academics and creators who want to study and extend the works of Joyce. Carol Shloss, a Joyce scholar, has worked for 15 years on a book about the ways in which the book Finnegans Wake was inspired by Joyce's mentally ill daughter. Joyce's grandson, Stephen Joyce, have allegedly destroyed documents relating to this to undermine her book.
+
+This isn't the first time that Stephen Joyce has hurt the cause of scholarship about his grandfather. He threatened to sue the Irish Museum over its exhibition of Joyce's papers. He threatened to sue pubs in Ireland for allowing people to read aloud from Joyce's novels on Bloomsday, the celebration of Ulysses. He told symphonic composers that they couldn't put Joyce quotations in their symphonies.
+
+Most tragically, there was a brief moment when Stephen Joyce was irrelevant. The works of James Joyce were in the public domain until the EU copyright directive extended copyright by 20 years, putting Joyce's books back into the care of his capricious grandson for decades.
+
+There's a whole body of scholarship devoted to tracking the ways in which Stephen Joyce has made himself the enemy of academics and Joyce lovers. The best work to start with is Matthew Rimmer's Bloomsday: Copyright Estates and Cultural Festivals.
+
+
+Before the book was published, publisher Farrar, Straus and Giroux removed several supporting citations from Shloss' tome to avoid a lawsuit, according to Olson. Shloss wants to post that information as an electronic appendix to answer several critics who charged that "To Dance in the Wake" was interesting, but thin on documentary evidence, Olson said.
+
+"It's painful once you've written something ... that you think is complete and good, to have it hacked up," Olson said. "There is a desire to bring it forth in the way she originally intended."
+
+Shloss prepared the Web site last year but never made it public because she worried about being sued, Olson said. Among the items excised from the book are quotations from "Finnegans Wake" she thinks support her thesis, as well as letters between James Joyce and his daughter, according to Olson.
+
+Shloss wants the court to declare she's entitled to use information the estate controls under laws that allow authors to quote copyrighted works if they do it in "a scholarly transformative manner."
+
+Update: This New Yorker article on the case is full of great color and background, and includes the fact that Larry Lessig, founder of the Creative Commons project, is arguing the case.
+
+
+
+
+
+Diyhappy took apart a Nokia 3200 -- which had interchangeable faceplates and was thus readily uncased -- and rebuilt it inside an old Nintendo Entertainment System controller. He dremelled out holes for the buttons and the screen and voila, the NES mobile phone.
+
+
+Link
+
+(Thanks, Sam!)
+
+
+
+ HOWTO make cufflinks out of Ethernet connectors
+
+
+
+Mark got invited to a fancy party and couldn't find his cufflinks, so he hacked a pair out of some Ethernet connectors and bits of wire; and thus the crimp-your-own cufflink was born. He's written up his mod in detail for others who want to follow suit.
+
+Link
+
+(Thanks, Mark!)
+
+
+
+
+
+ A British paper sent a reporter to "iPod City," the plant in Longhua, China, where iPods are assembled by women who earn $50/month for working 15 hour days.
+
+My guess is that this is no worse than the conditions in which Powerbooks, Thinkpads, Zens, Linksys routers, etc are manufactured, but Christ, this is depressing.
+
+
+ The Mail visited some of these factories and spoke with staff there. It reports that Foxconn's Longhua plant houses 200,000 workers, remarking: "This iPod City has a population bigger than Newcastle's."
+
+The report claims Longhua's workers live in dormitories that house 100 people, and that visitors from the outside world are not permitted. Workers toil for 15-hours a day to make the iconic music player, the report claims. They earn £27 per month. The report reveals that the iPod nano is made in a five-storey factory (E3) that is secured by police officers.
+
+Another factory in Suzhou, Shanghai, makes iPod shuffles. The workers are housed outside the plant, and earn £54 per month - but they must pay for their accommodation and food, "which takes up half their salaries", the report observes.
+
+
+
+Update: A former Nokia employee adds, "Add Nokia phones to your list. The type label may say 'Made in Finland' (top-notch models) or 'Made in Hungary' (mid-range ones), but Nokia cellphone engines (ie. the actual hardware) are manufactured by Foxconn in Longhua, China... unless they've found a cheaper supplier. Yes, I actually worked at the plant for a few months between real jobs."
+
+
+
+
+Colin Berry's Dave Alvin piece, which ran on KQED's "California Report" a couple weeks ago, is now available online.
+
+
Colin says: "Dave's new album [West of the West] is a tribute to California songwriters, including Tom Waits, Kate Wolf, Merle Haggard, Los Lobos, and others. I hung with him in the studio and talked to him (and some of the original songwriters) during the making of it."
+
+Link
+
+
+
+
+
+
+ Tim Biskup has created a tiny bronze sculpture to sell at his Laguna Art Museum retrospective (along with Gary Baseman).
+
+
Iki stands 2.25" tall, has dual faces, is limited to 44 signed and numbered pieces, and comes in a letterpressed packaging. Iki will be available at the Saturday opening (6.17.06, 8 - 10 PM) of Tim's joint retrospective Pervasion show with Gary Baseman at the Laguna Art Museum.
+ Covers from '60s French satirical magazine: Hara Kiri
+
+
+
+Here are a bunch of cover scans of a magazine I didn't know about until today. According to Wikipedia, Hara Kiri was created in 1960 and "in 1961 and 1966 they were temporarily banned by the French Government." Link
+
+
+
+
+
This is very late notice, but we (Negativland) want to let you and all
+Boingboingers know that we are playing live in LA. this Monday night,
+June 12th, at the Silent Movie Theater! Yes. We are. It's at 611
+North Fairfax Ave. Hollywood Box office- 323-655-2520. Tickets are
+$22. The doors are at 9pm and the show starts at 10pm sharp!
+
+
This is a very rare appearance for us in L.A, and at a really cool and
+intimate venue. The show is we are performing is called "It's All In
+Your Head FM", and we hope you can attend! It's about monotheism, but
+in stereo. With blindfolds handed out at the door. Really.
+ Meme Therapy has a long and interesting review with one of my very favorite authors, Rudy Rucker.
+
+
MT: What aspects of writing do you enjoy the most?
+
+
+
+RR: I like leaving the daily world and going to another world, a world that I had a hand in designing. You’ll notice that in most of my novels, the main character in fact leaves the world where I start him out and goes to another world. Another planet, another dimension, another sheet of reality. It’s an objective correlative for what I’m doing when I leave this mundane world and go into the world of my novel.
+
+
Writing is so much work. Every part of writing a novel is hard. The planning, the sitting down and creating, the revising. I guess the most fun part is when it seems to pour out and I’m having a good day. When I’m doing that, I stop worrying for a while, I forget myself and I’m happy and proud and even exalted and amazed to see what’s coming down or going up.
+
+
More precisely, that fun part is “the narcotic moment of creative bliss.” I just heard John Malkovich deliver that phrase, playing the role of an artist/art prof in Art School Confidential. That’s very right on; the operative word is “narcotic,” it’s definitely something you get addicted to over the years. Really I go to all this trouble writing a novel day after day month after month because, in a way, I’m trying to get high. Or see God. Or make love to the Muse. Waiting for the narcotic moment of creative bliss.
+
+
+Two years ago, artist Cayetano Ferrer took photos of the scene behind several Chicago street signs and then pasted the prints on top of the signs to achieve an amazing transparency effect. (As the Wooster Collective blog points out, Amnesty International's recent ad campaign employs a similar technique. And it's also the idea behind the "Transparent Screen" trick for your computer display.)
+Link to Ferrer's "City of Chicago" image gallery, Link to Amnesty International campaign (via Neatorama)
+
+
+
+ Illustrations from Rabelais's Gargantua and Pantagruel
+
+
+
+Bibliodyssey has posted two mind-blowing selections of surrealist characters from a 1565 publication called "Les Songes Drolatiques de Pantagruel, ou sont contenues plusieurs figures de l’invention de maistre François Rabelais : & derniere oeuvre d’iceluy, pour la recreation des bons esprits." While Rabelais is often credited with drawing the characters to accompany his text, they were apparently most likely drawn by François Desprez. The absurd monsters remind me of the wonderful phantasmagoric work of Jim Woodring.
+
+From Bibliodyssey:
+
+
Franciscan friar, doctor, traveller, model for the Thelemic magickal writings of Aleister Crowley, humanist, Benedictine monk, alchemist, teacher, leader of the French renaissance, heretic, greek scholar and groundbreaking satirical writer, François Rabelais (?1483/1493-1553) issued his magnum opus 'The life of Gargantua and Pantagruel' as a five book series over 20 years up to 1564.
+
+The books chart the humorous adventures of giants Gargantua and his son, Pantagruel in a scatalogical and often bawdy manner. Rabelais wrote in the epic tradition of Homer, and beyond the burlesque, there is an underlying serious examination of society, politics, education and philosophy whilst introducing 500 new words to the french lanugage.
+
+
+This isn't fair. Not only is Chris Ware a supremely gifted cartoonist, he can also play ragtime piano like nobody's business. Link(via Flog!)
+
+
Reader comment:
+
+Rob DeRose says:
+
+
Chris Ware shares his love of ragtime with MacArthur Genius Grant winner Reginald Robinson. In fact Chris heard Reginald playing in the winter garden of the Chicago Central Library one day and became fast friends. Here's a story from NPR on how the two of them found an entirely new song of Scott Joplin's. (its the fourth of four mini-segments.)
+
+
+
I've been a fan of Reginald ever since I saw him accompany the Squirrel Nut Zippers (in-between their first & second album) here in Chicago. If you get a chance to see him, by all means go. A nice Trib article about him. His CD on Amazon.
+
+
The Chicago Library's winter garden, where he used to practice, and where he & Chris Ware met (it's the nicest part of the building.)
+ Walt Disney's 1956 time-capsule letter to the future
+
+ The Disney company has unearthed a 1956 time-capsule containing a letter from Walt Disney to the future, on stationary bearing the legend "NO AGREEMENT WILL BE BINDING ON THIS CORPORATION UNLESS IN WRITING AND SIGNED BY AN OFFICER." Walt's letter to the future speculates about the future of entertainment and is at once profoundly wrong and profoundly right.
+
+Walt predicts that the world will be overturned by technology, all the old order remade. At the same time, he assumes that what will come in on the tails of 1956's mass media will be...more mass media! Even though Walt himself predated truly national media, he can't conceive of the age of mass media waning and being replaced by a mass medium -- a channel like the net -- crowded with a never-ending confusion of micro-media. Walt, in other words, didn't predict the long tail.
+
+
+[...O]f one thing I'm sure. People will need and demand amusement, refreshment and pleasant relaxation from daily tasks as much in your day as they have in ours and in all the generations of mankind into the remote past. What the exact nature and implementation of these mass entertainments may be, doesn't make much difference, it seems to me.
+
+Humanity, as history informs us, changes very slowly in character and basic interests. People need to play as much as they need toll. They never cease to be fascinated by they own powers and passions, their base or noble emotions, their faiths and struggles and triumphs against handicap -- all things that make them laugh and weep and comfort one another in love and sacrifice out of the depths of their being...
+
+Mindful of the phenomenal discoveries and applications of science to all our activities and institutions, it seems no mere guess that public entertainment will have become machined and powered by atomic and solar energies long before you read this capsule.
+
+The extension of radar and other as yet untapped sources of cosmic force may well have changed the entire technique of communication, in the theatre and television fields as well as in other areas of informational broadcast.
+
+Millions of people in massive assemblies around the world may now be viewing the same staged or natural event, scanned by some incredibly potent scope, in the same amount of time. They may even be viewing presently obscured vistas on neighboring planets as one might look at neighbors across our Los Angeles Streets.
+
+Omniscience will have drawn closer to finite senses and perceptions, for our entertainment as for our livelihood -- yours, I should say, who will read this in your 21st Century.
+
+
+200K PDF Link
+
+(Thanks, Anonymous Source!)
+
+
+
+ Plans for Barney Fife statue toppled by Knotts' estate
+
+ A couple of Barney Fife fans who put down $8,000 to erect a statue of Barney Fife (played by Mick Jagger lookalike Don Knotts) in downtown Mount Airy, NC (the model for Mayberry) received a letter from CBS attorneys telling them to halt the project.
+
+
+
+[CBS attorney] Mallory Levitt explained to [would-be statue erector Tom] Hellebrand and the Mount Airy News that although Paramount/CBS owned the rights to the character of Barney Fife, the group didn't have the authority to give permission for a likeness of Don Knotts.
+
+
"That right belongs to the Knotts estate," she said.
+
+
Levitt told Hellebrand she contacted the actor's estate and business associates of Andy Griffith, and none wanted to go through with the project.
+
+The project website, donknottsstatue.com, has a note about the cancellation of the project: "The tears on our pillows bespeak the pain that is in our hearts." The project leaders will be selling a full-size replica of a Mayberry Squad car and a golf cart made to look like a squad car on eBay to recoup their expenses.
+
+Link(Thanks for the correct, url, Dru!)
+
+
+
+
+
+At the Institute for the Future this morning, my colleague Mike Love is chugging this delicious and patriotic energy drink. Their tag line: "Makes you feel better all over than anywhere else." Ummm.... Link to Ol' Glory site, Link to Mike's photo on Flickr
+
+
+
+
+
+
+
+theFLOWmarket is a supermarket-as-artwork that sells consumer awareness in the form of imaginary products like "commercial free-space," "exploitation free produce," "symptom removers," "factory farming antibiotics," "renewable energy," and "a feeling of safety." The nicely-packaged products are available for sale at prices from $5 to $20. theFLOWmarket is open for business at the Danish Design Centre in Copenhagen.
+Link to Flash site (Thanks, Lindsay Tiemeyer!)
+
+
+
+ Pea-head smashes art gallery window, gets busted
+
+ Roq La Rue gallery Kirsten Anderson has a funny story about an idiot that smashed a window at her new gallery in Seattle, called BLVD. He might just be the stupidest brick-wielder on in the known universe. Read on...
+
+
+
+[A]fter I left and Damion was closing up, some drunk mouth-breathing knuckle-dragger starts banging on the door demanding to be let in. After Damion tells him that the gallery was closed, the Moron says "I'm going to smash your door in with a brick!" Damion at the time was talking to a couple of bad asses who offered to kick the guy's ass for us and looks like we should have taken them up on it, as an hour later, the guy pulls up to the gallery in his car, double parks, pulls a brick out of his car, and smashes BLVD's door a couple times. Cool huh? No one was in the gallery -- but the guy who lives upstairs heard it and called Damion. Also -- there is a bar a few storefronts away from us and I guess the folks on the patio saw it all. But it gets better. Moron turns to go back to his car and finds he's locked himself out. Har har! So he tries to smash his own car window in with the brick, which doesn't work... so he goes into the Rendevous to use the payphone to call a locksmith which is where he got nabbed by the cops. What a maroon. So anyway. Today is happy fun door repair day.
+ In yesterday's Washington Post, Joel Garreau, author of Radical Evolution, writes about the popularity of drugs like Adderall and Provigil to increase focus and wakefulness during academically stressful times. From the article:
+
"I'm a varsity athlete in crew," says Katharine Malone, a George Washington University junior. "So we're pretty careful about what we put in our bodies. So among my personal friends, I'd say the use is only like 50 or 60 percent..."
+For a senior project this semester, Christopher Salantrie conducted a random survey of 150 University of Delaware students at the university's Morris Library and Trabant Student Center.
+
+"With rising competition for admissions and classes becoming harder and harder by the day, a hypothesis was made that at least half of students at the university have at one point used/experienced such 'smart drugs,' " Salantrie writes in his report. He found his hunch easy to confirm.
+
+"What was a surprise, though, was the alarming rate of senior business majors who have used" the drugs, he writes. Almost 90 percent reported at least occasional use of "smart pills" at crunch times such as final exams, including Adderall, Ritalin, Strattera and others. Of those, three-quarters did not have a legitimate prescription, obtaining the pills from friends."
+
+
+Slate commissioned designers to produce six vintage pulp-fiction covers for classic novels like Moby Dick ("Primitive Pirate Passions Were a Prelude to Death!"), The Iliad ("Gore! Greeks! Glory!") and Alice in Wonderland ("One girl's drug-induced descent into dreamland debauchery"). The results are lovely.
+
+Link
+
+(Thanks, Fipi Lele!)
+
+
+
+
+
+ LotR video clip with voices replaced by foolish groans
+
+
+
+In this youtube, "CJ" has taken a clip from the Lord of the Rings trilogy in which Frodo awakens in the Elf stronghold and greets his comrades and replaced all the voices with idiotic groaning and moaning and squealing, apparently voiced by someone named Olaf. The net effect is surprisingly funny!
+
+Link
+
+(Thanks, Alice!)
+
+
+
+
+
+ Since June 1, William GIbson has been posting irregular chunks of prose to his blog, stuff that appears to be excerpts from a novel-in-progress. It's fascinating stuff, little vignettes that hint at a really exciting bigger picture.
+
+
+Vianca sat cross-legged on Tito’s floor, wearing a disposable hairnet and white knit cotton gloves, with his Sony plasma screen across her knees, going over it with an Armor All wipe. When she’d wiped it completely down, it would go back into its factory packaging, which in turn would be wiped down. Tito, in his own hairnet and gloves, sat opposite her, wiping the keys of his Casio. A carton of cleaning supplies had been waiting for them in the hall, beside a new and expensive-looking vacuum-cleaner Vianca said was German. Nothing came out of this vacuum but air, she said, so there would no stray hairs or other traces left behind. Tito had helped his cousin Eusebio with exactly this procedure, though Eusebio had mainly had books, each of which had needed, according to protocol, to be flipped through for forgotten insertions and then wiped. The reasons for Eusebio’s departure had never been made clear to him. That too was protocol.
+
+ Japanese anti-foreigner comic warns against human rights act
+
+
+
+Coal sez, "I've just translated and posted a rather well rendered manga from an 'emergency publication' in Japan about the dangers of protecting human rights. Japan is a little behind in legal recognition of basic human rights (including but not limited to racial discrimination etc.), and it seems the emergence of a bill to make protection of rights enforceable has a few people worried. The level of alarmism I think is particularly amusing, if that's the right word. What's also noteworthy is the constant demonising of trouble-making foreigners, and the pity the writer tries to inspire for the poor landlord who can no longer refuse to rent his house to Chinese etc. You can't make this stuff up!"
+
+
+Link
+
+(Thanks, Coal!)
+
+
+
+ iPod Nano boombox built into flashlight casing
+
+
+
+Here's a monaural boombox built into the housing for a big Eveready flashlight. The speaker fits over the mouth, and it sits over a miniature amp scavegened from a set of desktop speakers and an iPod Nano with a wireless remote.
+
+Link to parts-list, Link to finished item
+
+
+
+
+
+ New Barenaked Ladies single as free, remixable multitracks
+
+
+The Canadian band Barenaked Ladies have pre-released a track from their upcoming album Barenaked Ladies Are Me, in a four-track mix that's ready for remixing, and free. They're planning to do more of the same with their future releases.
+
+I used to see BNL play at my local shopping mall, the Scarborough Town Centre, when all they'd released was an indie cassette tape with an amazing cover of Public Enemy's "Fight the Power" on it, and I'm so amazingly glad to see them still making great music. What's more, the band's frontman, Steve Page, is also fronting a group of Canadian musicians who've spoken out against DRM and suing fans and other music label shenanigans.
+
+Best of all -- they're releasing the next album as a 15-song digital version as well as a 13-song CD, so I can get their music without having to take another piece of slow-decaying, space-hogging media into my already overcrowded home.
+
+Link
+
+(Thanks, Frank!)
+
+
+
+
+
+ Responses to Jaron Lanier's crit of online collectivism
+
+ Two weeks ago, Edge.org published Jaron Lanier's essay "Digital Maoism: The Hazards of the New Online Collectivism," critiquing the importance people are now placing on Wikipedia and other examples of the "hive mind," as people called it in the cyberdelic early 1990s. It's an engaging essay to be sure, but much more thought-provoking to me are the responses from the likes of Clay Shirky, Dan Gillmor, Howard Rheingold, our own Cory Doctorow, Douglas Rushkoff, and, of course, Jimmy Wales.
I have a hard time fearing that the participants of Wikipedia or even the call-in voters of American Idol will be in a position to remake the social order anytime, soon. And I'm concerned that any argument against collaborative activity look fairly at the real reasons why some efforts turn out the way they do. Our fledgling collective intelligences are not emerging in a vacuum, but on media platforms with very specific biases.
+
+First off, we can't go on pretending that even our favorite disintermediation efforts are revolutions in any real sense of the word. Projects like Wikipedia do not overthrow any elite at all, but merely replace one elite — in this case an academic one — with another: the interactive media elite...
+
+While it may be true that a large number of current websites and group projects contain more content aggregation (links) than original works (stuff), that may as well be a critique of the entirety of Western culture since post-modernism. I'm as tired as anyone of art and thought that exists entirely in the realm of context and reference — but you can't blame Wikipedia for architecture based on winks to earlier eras or a music culture obsessed with sampling old recordings instead of playing new compositions.
+
+Honestly, the loudest outcry over our Internet culture's inclination towards re-framing and the "meta" tend to come from those with the most to lose in a society where "credit" is no longer a paramount concern. Most of us who work in or around science and technology understand that our greatest achievements are not personal accomplishments but lucky articulations of collective realizations. Something in the air... Claiming authorship is really just a matter of ego and royalties.
+
Wikipedia isn't great because it's like the Britannica. The Britannica is great at being authoritative, edited, expensive, and monolithic. Wikipedia is great at being free, brawling, universal, and instantaneous.
+
+From Jimmy Wales (italics indicate quotes from Jaron's original essay):
+
+
+
"A core belief of the wiki world is that whatever problems exist in the wiki will be incrementally corrected as the process unfolds."
+
+My response is quite simple: this alleged "core belief" is not one which is held by me, nor as far as I know, by any important or prominent Wikipedians. Nor do we have any particular faith in collectives or collectivism as a mode of writing. Authoring at Wikipedia, as everywhere, is done by individuals exercising the judgment of their own minds.
+
+ "The best guiding principle is to always cherish individuals first."
+
+UPDATE: Jaron Lanier writes us that he's received a lot of negative feedback from people who he thinks may not have actually read his original essay:
+
+In the essay i criticized the desire (that has only recently become influential) to create an "oracle effect" out of anonymity on the internet - that's the thing i identified as being a new type of collectivism, but i did not make that accusation against the wikipedia - or against social cooperation on the net, which is something i was an early true believer in- if i remember those weird days well, i think i even made up some of the rhetoric and terminology that is still associated with net advocacy today- anyway, i specifically exempted many internet gatherings from my criticism, including the wikipedia, boingboing, google, cool tools... and also the substance of the essay was not accusatory but constructive- the three rules i proposed for creating effective feedback links to the "hive mind" being one example.
+ This has been going around for a couple of days, but I just found out about it. It's a neat optical effect -- you stare at a color negative of a photo for 30 seconds (or even just 15), then move the mouse over the photo, keeping your eyes on the black dot. The photo appears in color, until you move your eyes. Link
+
+
+
+ Danny sez, "Line Noise is the new EFF podcast (RSS or iTunes); this week's episode is a chat with EFF's IP attorney Fred von Lohmann on the background to the Section 115 Reform Act (previously on Boing Boing. He explains how a good bill was used to sneak in bad precedents - including the insane idea that all temporarily cached copies on the Net and in RAM should be copyrightable and subject to licensing.
+
+"Good news on that, by the way -- thanks to your calls and comments, the committee have slowed the pace of this fast-track bill, and are now working to fix the bill's language. Everyone from the Copyright Office to Radio Shack and BellSouth have now commented on the problems, so there's an excellent chance of a clear resolution."
+
+Link
+
+
+
+ Why do these people have characters on their foreheads?
+
+ Nick of Square America invites you to solve a mystery.
+
+
I got this lot of slides about three years ago and I've never been able to figure out just what is going on. There are about 50 slides in all- all dating from between 1959 and 1969 and all of young women. Some, like the ones here have letters written on their foreheads, others have press type with their names on it affixed to either their temples or foreheads. Were the slides taken by a dermatologist or plastic surgeon or were these young women part of some now forgotten experiment.
+ Trailer for 2007 Disney Pixar movie: Ratatouille
+
+
+
+Apple has the trailer for the next Disney Pixar movie coming out in 2007. It's called Ratatouille and it appears to be about a Parisian rat (without a phony French accent) who, unlike other rats in his family, insists on eating only the finest food served in Paris' best restaurants.
+
+
The quality of the video is really nice. Don't you wish YouTube looked half as nice as this? Link
+
+
+
+ More great old illustrations from BilbiOdyssey
+
+
+
+
+
+Why are so many drawings from earlier centuries so deliciously weird? Here are a couple I came across on one of my favorite blogs, BibliOdyssey. Link
+
+
+
+ Wired News tells how to watch FIFA World Cup for free online
+
+ A while back, law firm Baker & McKenzie sent Boing Boing a snippy letter warning us not to do something we wouldn't do even if they begged us -- broadcast live streams of the FIFA World Cup.
+
+
I wonder if Baker & McKenzie will send Wired News a letter complaining that Wired News is facilitating piracy for explaining a variety of ways in which FIFA World Cup fans can enjoy live video streams of the tournament on their computers without paying the rightsholder, Infront Sports & Media?
+
+ Link
fSubSub=myInsDoc('Asymmetric Unit /<br> Biological Molecule',fSub,'S','/pdb/static.do?p=explorer/singleimage.jsp&structureId=1cy0&type=asym&size=500');
fSubSub=myInsDoc('Structure Explorer Intro',fSub,'S','javascript:callHelp(roboLoc,\'structure_explorer/introduction_to_structure_explorer.htm\');',ICONPATH+'question.gif');
fSubSub=myInsDoc('Biology & Chemistry',fSub,'S','javascript:callHelp(roboLoc,\'quick_links/quick_links_biology_and_chemistry.htm\');',ICONPATH+'question.gif');
fSubSub=myInsDoc('Materials & Methods (X-Ray)',fSub,'S','javascript:callHelp(roboLoc,\'quick_links/materials_and_methods/x-ray_materials_and_methods.htm\');',ICONPATH+'question.gif');
fSubSub=myInsDoc('Materials & Methods (NMR)',fSub,'S','javascript:callHelp(roboLoc,\'quick_links/materials_and_methods/nmr_materials_and_methods.htm\');',ICONPATH+'question.gif');
<tdwidth="210"><ahref="/pdb"><imgalt="RCSB PDB Protein Data Bank | Home"title="RCSB PDB Protein Data Bank | Home"src="/pdb/skins/pastel/images/header/pdblogo.gif"width="198"border="0"></a></td>
<ahref="http://www.wwpdb.org/"target="_blank"><imgalt="A Member of the wwPDB"title="A Member of the wwPDB"src="/pdb/skins/pastel/images/header/wwpdb.gif"width="191"height="15"border="0"></a><br/>
As of <ahref="/pdb/search/smartSubquery.do?smartSearchSubtype=LastLoadQuery">Tuesday Dec 26, 2006</a> <ahref="/pdb/rss/LastLoad"title="RSS Feed for the Latest Released Structures"><imgalt="RSS Feed for the Latest Released Structures"border="0"src="/pdbstatic/images/feed-icon16x16.png"></a>
<inputtype="radio"name="radioset"value="All"checkedclass="radio"onclick="javascript:document.headerQueryForm.isAuthorSearch.value='no';">PDB ID or keyword
<noscript><divstyle="padding-left:8px;font-weight:bold;color:#FF0000;font-size:16px">This browser is either not Javascript enabled or has it turned off.<br/>This site will not function correctly without Javascript.</div></noscript>
<spanclass="se_subitem">EC no.:</span> <aclass="se_datasmall"onclick="searchEc('5.99.1.2');"onmouseover="this.className='se_datasmallHover'"onmouseout="this.className='se_datasmall'">5.99.1.2</a> <aclass="se_datalarge"href="http://www.chem.qmul.ac.uk/iubmb/enzyme/EC5/99/1/2.html"target="resource_window"><imgsrc="/pdbstatic/explorer/images/iubmb_icon.gif"BORDER="0"ALT="Go to IUBMB EC entry"TITLE="Go to IUBMB EC entry"></a>
<aclass="se_datalarge"href="http://www.ncbi.nlm.nih.gov/Taxonomy/Browser/wwwtax.cgi?id=562"target="resource_window"><imgsrc="/pdbstatic/explorer/images/taxonomy_icon.gif"BORDER="0"ALT="Go to NCBI Taxonomy entry"TITLE="Go to NCBI Taxonomy entry"></a>
<aclass="se_datasmall"href="/pdb/search/smartSubquery.do?smartSearchSubtype=TreeQuery&t=11&n=56714"> DNA topoisomerase I, 67K N-terminal domain</a>