]
+ @markup.add_special(/(((\{.*?\})|\b\S+?)\[\S+?\.\S+?\])/, :TIDYLINK)
+ # @markup.add_special(/\b(\S+?\[\S+?\.\S+?\])/, :TIDYLINK)
+
+ end
+ unless defined? @html_formatter
+ @html_formatter = HyperlinkHtml.new(self.path, self)
+ end
+
+ # Convert leading comment markers to spaces, but only
+ # if all non-blank lines have them
+
+ if str =~ /^(?>\s*)[^\#]/
+ content = str
+ else
+ content = str.gsub(/^\s*(#+)/) { $1.tr('#',' ') }
+ end
+
+ res = @markup.convert(content, @html_formatter)
+ if remove_para
+ res.sub!(/^/, '')
+ res.sub!(/<\/p>$/, '')
+ end
+ res
+ end
+
+
+ def style_url(path, css_name=nil)
+ css_name ||= CSS_NAME
+ end
+
+ # Build a webcvs URL with the given 'url' argument. URLs with a '%s' in them
+ # get the file's path sprintfed into them; otherwise they're just catenated
+ # together.
+
+ def cvs_url(url, full_path)
+ if /%s/ =~ url
+ return sprintf( url, full_path )
+ else
+ return url + full_path
+ end
+ end
+ end
+
+
+ #####################################################################
+ #
+ # A Context is built by the parser to represent a container: contexts
+ # hold classes, modules, methods, require lists and include lists.
+ # ClassModule and TopLevel are the context objects we process here
+ #
+ class ContextUser
+
+ include MarkUp
+
+ attr_reader :context
+
+ def initialize(context, options)
+ @context = context
+ @options = options
+
+ end
+
+ # convenience method to build a hyperlink # Where's the DRY in this?? Put this in the template where it belongs
+ def href(link, cls, name)
+ %{"#{name} "}
+ end
+
+ # Create a list of HtmlMethod objects for each method
+ # in the corresponding context object. If the @options.show_all
+ # variable is set (corresponding to the --all option,
+ # we include all methods, otherwise just the public ones.
+
+ def collect_methods
+ list = @context.method_list
+ unless @options.show_all
+ list = list.find_all {|m| m.visibility == :public || m.visibility == :protected || m.force_documentation }
+ end
+ @methods = list.collect {|m| HtmlMethod.new(m, self, @options) }
+ end
+
+ # Build a summary list of all the methods in this context
+ def build_method_summary_list(path_prefix="")
+ collect_methods unless @methods
+ meths = @methods.sort
+ res = []
+ meths.each do |meth|
+ res << {
+ "name" => CGI.escapeHTML(meth.name),
+ "aref" => meth.aref,
+ "href" => meth.path
+ }
+ end
+ res
+ end
+
+
+ # Build a list of aliases for which we couldn't find a
+ # corresponding method
+ def build_alias_summary_list(section)
+ values = []
+ @context.aliases.each do |al|
+ next unless al.section == section
+ res = {
+ 'old_name' => al.old_name,
+ 'new_name' => al.new_name,
+ }
+ if al.comment && !al.comment.empty?
+ res['desc'] = markup(al.comment, true)
+ end
+ values << res
+ end
+ values
+ end
+
+ # Build a list of constants
+ def build_constants_summary_list(section)
+ values = []
+ @context.constants.each do |co|
+ next unless co.section == section
+ res = {
+ 'name' => co.name,
+ 'value' => CGI.escapeHTML(co.value)
+ }
+ res['desc'] = markup(co.comment, true) if co.comment && !co.comment.empty?
+ values << res
+ end
+ values
+ end
+
+ def build_requires_list(context)
+ potentially_referenced_list(context.requires) {|fn| [fn + ".rb"] }
+ end
+
+ def build_include_list(context)
+ potentially_referenced_list(context.includes)
+ end
+
+ # Build a list from an array of Htmlxxx items. Look up each
+ # in the AllReferences hash: if we find a corresponding entry,
+ # we generate a hyperlink to it, otherwise just output the name.
+ # However, some names potentially need massaging. For example,
+ # you may require a Ruby file without the .rb extension,
+ # but the file names we know about may have it. To deal with
+ # this, we pass in a block which performs the massaging,
+ # returning an array of alternative names to match
+
+ def potentially_referenced_list(array)
+ res = []
+ array.each do |i|
+ ref = AllReferences[i.name]
+ # if !ref
+ # container = @context.parent
+ # while !ref && container
+ # name = container.name + "::" + i.name
+ # ref = AllReferences[name]
+ # container = container.parent
+ # end
+ # end
+
+ ref = @context.find_symbol(i.name)
+ ref = ref.viewer if ref
+
+ if !ref && block_given?
+ possibles = yield(i.name)
+ while !ref and !possibles.empty?
+ ref = AllReferences[possibles.shift]
+ end
+ end
+ h_name = CGI.escapeHTML(i.name)
+ if ref and ref.document_self
+ path = ref.path
+ res << { "name" => h_name, "href" => path }
+ else
+ res << { "name" => h_name, "href" => "" }
+ end
+ end
+ res
+ end
+
+ # Build an array of arrays of method details. The outer array has up
+ # to six entries, public, private, and protected for both class
+ # methods, the other for instance methods. The inner arrays contain
+ # a hash for each method
+
+ def build_method_detail_list(section)
+ outer = []
+
+ methods = @methods.sort
+ for singleton in [true, false]
+ for vis in [ :public, :protected, :private ]
+ res = []
+ methods.each do |m|
+ if m.section == section and
+ m.document_self and
+ m.visibility == vis and
+ m.singleton == singleton
+ row = {}
+ if m.call_seq
+ row["callseq"] = m.call_seq.gsub(/->/, '→')
+ else
+ row["name"] = CGI.escapeHTML(m.name)
+ row["params"] = m.params
+ end
+ desc = m.description.strip
+ row["m_desc"] = desc unless desc.empty?
+ row["aref"] = m.aref
+ row["href"] = m.path
+ row["m_seq"] = m.seq
+ row["visibility"] = m.visibility.to_s
+
+ alias_names = []
+ m.aliases.each do |other|
+ if other.viewer # won't be if the alias is private
+ alias_names << {
+ 'name' => other.name,
+ 'href' => other.viewer.path,
+ 'aref' => other.viewer.aref
+ }
+ end
+ end
+ unless alias_names.empty?
+ row["aka"] = alias_names
+ end
+
+ #if @options.inline_source
+ code = m.source_code
+ row["sourcecode"] = code if code
+ #else
+ # code = m.src_url
+ #if code
+ # row["codeurl"] = code
+ # row["imgurl"] = m.img_url
+ #end
+ #end
+ res << row
+ end
+ end
+ if res.size > 0
+ outer << {
+ "type" => vis.to_s.capitalize,
+ "category" => singleton ? "Class" : "Instance",
+ "methods" => res
+ }
+ end
+ end
+ end
+ outer
+ end
+
+ # Build the structured list of classes and modules contained
+ # in this context.
+
+ def build_class_list(level, from, section, infile=nil)
+ res = ""
+ prefix = " ::" * level;
+
+ from.modules.sort.each do |mod|
+ next unless mod.section == section
+ next if infile && !mod.defined_in?(infile)
+ if mod.document_self
+ res <<
+ prefix <<
+ "Module " <<
+ href(mod.viewer.path, "link", mod.full_name) <<
+ " \n" <<
+ build_class_list(level + 1, mod, section, infile)
+ end
+ end
+
+ from.classes.sort.each do |cls|
+ next unless cls.section == section
+ next if infile && !cls.defined_in?(infile)
+ if cls.document_self
+ res <<
+ prefix <<
+ "Class " <<
+ href(cls.viewer.path, "link", cls.full_name) <<
+ " \n" <<
+ build_class_list(level + 1, cls, section, infile)
+ end
+ end
+
+ res
+ end
+
+ def document_self
+ @context.document_self
+ end
+
+ def diagram_reference(diagram)
+ res = diagram.gsub(/((?:src|href)=")(.*?)"/) {
+ $1 + $2 + '"'
+ }
+ res
+ end
+
+
+ # Find a symbol in ourselves or our parent
+ def find_symbol(symbol, method=nil)
+ res = @context.find_symbol(symbol, method)
+ if res
+ res = res.viewer
+ end
+ res
+ end
+
+ # create table of contents if we contain sections
+
+ def add_table_of_sections
+ toc = []
+ @context.sections.each do |section|
+ if section.title
+ toc << {
+ 'secname' => section.title,
+ 'href' => section.sequence
+ }
+ end
+ end
+
+ @values['toc'] = toc unless toc.empty?
+ end
+
+
+ end
+
+ #####################################################################
+ #
+ # Wrap a ClassModule context
+
+ class HtmlClass < ContextUser
+
+ @@c_seq = "C00000000"
+
+ attr_reader :path
+
+ def initialize(context, html_file, prefix, options)
+ super(context, options)
+ @@c_seq = @@c_seq.succ
+ @c_seq = @@c_seq
+ @html_file = html_file
+ @is_module = context.is_module?
+ @values = {}
+
+ context.viewer = self
+
+ @path = http_url(context.full_name, prefix)
+
+ collect_methods
+
+ AllReferences.add(name, self)
+ end
+
+ # return the relative file name to store this class in,
+ # which is also its url
+ def http_url(full_name, prefix)
+ path = full_name.dup
+ if path['<<']
+ path.gsub!(/<<\s*(\w*)/) { "from-#$1" }
+ end
+ File.join(prefix, path.split("::")) + ".html"
+ end
+
+ def seq
+ @c_seq
+ end
+
+ def aref
+ @c_seq
+ end
+
+ def scope
+ a = @context.full_name.split("::")
+ if a.length > 1
+ a.pop
+ a.join("::")
+ else
+ ""
+ end
+ end
+
+ def name
+ @context.full_name.gsub("#{scope}::", '')
+ end
+
+ def full_name
+ @context.full_name
+ end
+
+ def parent_name
+ @context.parent.full_name
+ end
+
+ def write_on(f)
+ value_hash
+ template = TemplatePage.new(RDoc::Page::BODY,
+ RDoc::Page::CLASS_PAGE,
+ RDoc::Page::METHOD_LIST)
+ template.write_html_on(f, @values)
+ end
+
+ def value_hash
+ class_attribute_values
+ add_table_of_sections
+
+ @values["charset"] = @options.charset
+ @values["style_url"] = style_url(path, @options.css)
+
+ # Convert README to html
+ unless File.exist?('files/README.html')
+ File.open('files/README.html', 'w') do |file|
+ file << markup(File.read(File.expand_path(@options.main_page)))
+ end
+ end
+
+ d = markup(@context.comment)
+ @values["description"] = d unless d.empty?
+
+ ml = build_method_summary_list
+ @values["methods"] = ml unless ml.empty?
+
+ il = build_include_list(@context)
+ @values["includes"] = il unless il.empty?
+
+ @values["sections"] = @context.sections.map do |section|
+
+ secdata = {
+ "sectitle" => section.title,
+ "secsequence" => section.sequence,
+ "seccomment" => markup(section.comment)
+ }
+
+ al = build_alias_summary_list(section)
+ secdata["aliases"] = al unless al.empty?
+
+ co = build_constants_summary_list(section)
+ secdata["constants"] = co unless co.empty?
+
+ al = build_attribute_list(section)
+ secdata["attributes"] = al unless al.empty?
+
+ cl = build_class_list(0, @context, section)
+ secdata["classlist"] = cl unless cl.empty?
+
+ mdl = build_method_detail_list(section)
+ secdata["method_list"] = mdl unless mdl.empty?
+
+ secdata
+ end
+
+ @values
+ end
+
+ def build_attribute_list(section)
+ atts = @context.attributes.sort
+ res = []
+ atts.each do |att|
+ next unless att.section == section
+ if att.visibility == :public || att.visibility == :protected || @options.show_all
+ entry = {
+ "name" => CGI.escapeHTML(att.name),
+ "rw" => att.rw,
+ "a_desc" => markup(att.comment, true)
+ }
+ unless att.visibility == :public || att.visibility == :protected
+ entry["rw"] << "-"
+ end
+ res << entry
+ end
+ end
+ res
+ end
+
+ def class_attribute_values
+ h_name = CGI.escapeHTML(name)
+
+ @values["classmod"] = @is_module ? "Module" : "Class"
+ @values["title"] = "#{@values['classmod']}: #{h_name}"
+
+ c = @context
+ c = c.parent while c and !c.diagram
+ if c && c.diagram
+ @values["diagram"] = diagram_reference(c.diagram)
+ end
+
+ @values["full_name"] = h_name
+ @values["class_seq"] = seq
+ parent_class = @context.superclass
+
+ if parent_class
+ @values["parent"] = CGI.escapeHTML(parent_class)
+
+ if parent_name
+ lookup = parent_name + "::" + parent_class
+ else
+ lookup = parent_class
+ end
+
+ parent_url = AllReferences[lookup] || AllReferences[parent_class]
+
+ if parent_url and parent_url.document_self
+ @values["par_url"] = parent_url.path
+ end
+ end
+
+ files = []
+ @context.in_files.each do |f|
+ res = {}
+ full_path = CGI.escapeHTML(f.file_absolute_name)
+
+ res["full_path"] = full_path
+ res["full_path_url"] = f.viewer.path if f.document_self
+
+ if @options.webcvs
+ res["cvsurl"] = cvs_url( @options.webcvs, full_path )
+ end
+
+ files << res
+ end
+
+ @values['infiles'] = files
+ end
+
+ def <=>(other)
+ self.name <=> other.name
+ end
+
+ end
+
+ #####################################################################
+ #
+ # Handles the mapping of a file's information to HTML. In reality,
+ # a file corresponds to a +TopLevel+ object, containing modules,
+ # classes, and top-level methods. In theory it _could_ contain
+ # attributes and aliases, but we ignore these for now.
+
+ class HtmlFile < ContextUser
+
+ @@f_seq = "F00000000"
+
+ attr_reader :path
+ attr_reader :name
+
+ def initialize(context, options, file_dir)
+ super(context, options)
+ @@f_seq = @@f_seq.succ
+ @f_seq = @@f_seq
+ @values = {}
+
+ @path = http_url(file_dir)
+ @source_file_path = File.expand_path(@context.file_relative_name).gsub("\/doc\/", "/")
+ @name = @context.file_relative_name
+
+ collect_methods
+ AllReferences.add(name, self)
+ context.viewer = self
+ end
+
+ def http_url(file_dir)
+ File.join(file_dir, @context.file_relative_name.tr('.', '_')) + ".html"
+ end
+
+ def filename_to_label
+ @context.file_relative_name.gsub(/%|\/|\?|\#/) {|s| '%' + ("%x" % s[0]) }
+ end
+
+ def seq
+ @f_seq
+ end
+
+ def aref
+ @f_seq
+ end
+
+ def name
+ full_path = @context.file_absolute_name
+ short_name = File.basename(full_path)
+ end
+
+ def full_name
+ @context.file_absolute_name
+ end
+
+ def scope
+ @context.file_relative_name.gsub(/\/#{name}$/, '')
+ end
+
+ def parent_name
+ nil
+ end
+
+ def full_file_source
+ ret_str = ""
+ File.open(@source_file_path, 'r') do |f|
+ while(!f.eof?) do
+ ret_str += f.readline()
+ end
+ end
+ ret_str
+ rescue
+ "file not found -#{@source_file_path}-"
+ #@source_file_path
+ end
+
+ def value_hash
+ file_attribute_values
+ add_table_of_sections
+
+ @values["charset"] = @options.charset
+ @values["href"] = path
+ @values["style_url"] = style_url(path, @options.css)
+ @values["file_seq"] = seq
+
+ #pulling in the source for this file
+ #@values["source_code"] = @context.token_stream
+
+ @values["file_source_code"] = CGI.escapeHTML(full_file_source)
+
+ if @context.comment
+ d = markup(@context.comment)
+ @values["description"] = d if d.size > 0
+ end
+
+ ml = build_method_summary_list
+ @values["methods"] = ml unless ml.empty?
+
+ il = build_include_list(@context)
+ @values["includes"] = il unless il.empty?
+
+ rl = build_requires_list(@context)
+ @values["requires"] = rl unless rl.empty?
+
+
+ file_context = @context
+
+ @values["sections"] = @context.sections.map do |section|
+
+ secdata = {
+ "sectitle" => section.title,
+ "secsequence" => section.sequence,
+ "seccomment" => markup(section.comment)
+ }
+
+ cl = build_class_list(0, @context, section, file_context)
+ @values["classlist"] = cl unless cl.empty?
+
+ mdl = build_method_detail_list(section)
+ secdata["method_list"] = mdl unless mdl.empty?
+
+ al = build_alias_summary_list(section)
+ secdata["aliases"] = al unless al.empty?
+
+ co = build_constants_summary_list(section)
+ @values["constants"] = co unless co.empty?
+
+ secdata
+ end
+
+ @values
+ end
+
+ def write_on(f)
+ value_hash
+ template = TemplatePage.new(RDoc::Page::SRC_BODY,RDoc::Page::FILE_PAGE, RDoc::Page::METHOD_LIST)
+ template.write_html_on(f, @values)
+ end
+
+ def file_attribute_values
+ full_path = @context.file_absolute_name
+ short_name = File.basename(full_path)
+
+ @values["title"] = CGI.escapeHTML("File: #{short_name}")
+
+ if @context.diagram
+ @values["diagram"] = diagram_reference(@context.diagram)
+ end
+
+ @values["short_name"] = CGI.escapeHTML(short_name)
+ @values["full_path"] = CGI.escapeHTML(full_path)
+ @values["dtm_modified"] = @context.file_stat.mtime.to_s
+
+ if @options.webcvs
+ @values["cvsurl"] = cvs_url( @options.webcvs, @values["full_path"] )
+ end
+ end
+
+ def <=>(other)
+ self.name <=> other.name
+ end
+ end
+
+ #####################################################################
+
+ class HtmlMethod
+ include MarkUp
+
+ attr_reader :context
+ attr_reader :src_url
+ attr_reader :img_url
+ attr_reader :source_code
+
+ @@m_seq = "M000000"
+
+ @@all_methods = []
+
+ def HtmlMethod::reset
+ @@all_methods = []
+ end
+
+ def initialize(context, html_class, options)
+ @context = context
+ @html_class = html_class
+ @options = options
+ @@m_seq = @@m_seq.succ
+ @m_seq = @@m_seq
+ @@all_methods << self
+
+ context.viewer = self
+
+ if (ts = @context.token_stream)
+ @source_code = markup_code(ts)
+ #unless @options.inline_source
+ # @src_url = create_source_code_file(@source_code)
+ # @img_url = MERBGenerator.gen_url(path, 'source.png')
+ #end
+ end
+ AllReferences.add(name, self)
+ end
+
+ def seq
+ @m_seq
+ end
+
+ def aref
+ @m_seq
+ end
+
+ def scope
+ @html_class.full_name
+ end
+
+ # return a reference to outselves to be used as an href=
+ # the form depends on whether we're all in one file
+ # or in multiple files
+
+ def name
+ @context.name
+ end
+
+ def section
+ @context.section
+ end
+
+ def parent_name
+ if @context.parent.parent
+ @context.parent.parent.full_name
+ else
+ nil
+ end
+ end
+
+ def path
+ @html_class.path
+ end
+
+ def description
+ markup(@context.comment)
+ end
+
+ def visibility
+ @context.visibility
+ end
+
+ def singleton
+ @context.singleton
+ end
+
+ def call_seq
+ cs = @context.call_seq
+ if cs
+ cs.gsub(/\n/, " \n")
+ else
+ nil
+ end
+ end
+
+ def params
+ # params coming from a call-seq in 'C' will start with the
+ # method name
+ p = @context.params
+ if p !~ /^\w/
+ p = @context.params.gsub(/\s*\#.*/, '')
+ p = p.tr("\n", " ").squeeze(" ")
+ p = "(" + p + ")" unless p[0] == ?(
+
+ if (block = @context.block_params)
+ # If this method has explicit block parameters, remove any
+ # explicit &block
+
+ p.sub!(/,?\s*&\w+/, '')
+
+ block.gsub!(/\s*\#.*/, '')
+ block = block.tr("\n", " ").squeeze(" ")
+ if block[0] == ?(
+ block.sub!(/^\(/, '').sub!(/\)/, '')
+ end
+ p << " {|#{block.strip}| ...}"
+ end
+ end
+ CGI.escapeHTML(p)
+ end
+
+ def create_source_code_file(code_body)
+ meth_path = @html_class.path.sub(/\.html$/, '.src')
+ File.makedirs(meth_path)
+ file_path = File.join(meth_path, seq) + ".html"
+
+ template = TemplatePage.new(RDoc::Page::SRC_PAGE)
+ File.open(file_path, "w") do |f|
+ values = {
+ 'title' => CGI.escapeHTML(name),
+ 'code' => code_body,
+ 'style_url' => style_url(file_path, @options.css),
+ 'charset' => @options.charset
+ }
+ template.write_html_on(f, values)
+ end
+ file_path
+ end
+
+ def HtmlMethod.all_methods
+ @@all_methods
+ end
+
+ def <=>(other)
+ @context <=> other.context
+ end
+
+ ##
+ # Given a sequence of source tokens, mark up the source code
+ # to make it look purty.
+
+
+ def markup_code(tokens)
+ src = ""
+ tokens.each do |t|
+ next unless t
+ # p t.class
+ # style = STYLE_MAP[t.class]
+ style = case t
+ when RubyToken::TkCONSTANT then "ruby-constant"
+ when RubyToken::TkKW then "ruby-keyword kw"
+ when RubyToken::TkIVAR then "ruby-ivar"
+ when RubyToken::TkOp then "ruby-operator"
+ when RubyToken::TkId then "ruby-identifier"
+ when RubyToken::TkNode then "ruby-node"
+ when RubyToken::TkCOMMENT then "ruby-comment cmt"
+ when RubyToken::TkREGEXP then "ruby-regexp re"
+ when RubyToken::TkSTRING then "ruby-value str"
+ when RubyToken::TkVal then "ruby-value"
+ else
+ nil
+ end
+
+ text = CGI.escapeHTML(t.text)
+
+ if style
+ src << "#{text} "
+ else
+ src << text
+ end
+ end
+
+ add_line_numbers(src)
+ src
+ end
+
+ # we rely on the fact that the first line of a source code
+ # listing has
+ # # File xxxxx, line dddd
+
+ def add_line_numbers(src)
+ if src =~ /\A.*, line (\d+)/
+ first = $1.to_i - 1
+ last = first + src.count("\n")
+ size = last.to_s.length
+ real_fmt = "%#{size}d: "
+ fmt = " " * (size+2)
+ src.gsub!(/^/) do
+ res = sprintf(fmt, first)
+ first += 1
+ fmt = real_fmt
+ res
+ end
+ end
+ end
+
+ def document_self
+ @context.document_self
+ end
+
+ def aliases
+ @context.aliases
+ end
+
+ def find_symbol(symbol, method=nil)
+ res = @context.parent.find_symbol(symbol, method)
+ if res
+ res = res.viewer
+ end
+ res
+ end
+ end
+
+ #####################################################################
+
+ class MERBGenerator
+
+ include MarkUp
+
+ # Generators may need to return specific subclasses depending
+ # on the options they are passed. Because of this
+ # we create them using a factory
+
+ def MERBGenerator.for(options)
+ AllReferences::reset
+ HtmlMethod::reset
+
+ MERBGenerator.new(options)
+
+ end
+
+ class < "helvetica"} #this is not used anywhere but the template function demands a hash of values
+ template.write_html_on(f, values)
+ end
+ end
+
+ def write_javascript
+ #Argh... I couldn't figure out how to copy these from the template dir so they were copied into
+ # the template file "ajax.rb" and processed similarlly to the style sheets. Not exactly a good thing to do with
+ # external library code. Not very DRY.
+
+ File.open("api_grease.js", "w") do |f|
+ f << RDoc::Page::API_GREASE_JS
+ end
+
+ File.open("prototype.js", "w") do |f|
+ f << RDoc::Page::PROTOTYPE_JS
+ end
+
+ rescue LoadError
+ $stderr.puts "Could not find AJAX template"
+ exit 99
+ end
+
+ ##
+ # See the comments at the top for a description of the
+ # directory structure
+
+ def gen_sub_directories
+ File.makedirs(FILE_DIR, CLASS_DIR)
+ rescue
+ $stderr.puts $!.message
+ exit 1
+ end
+
+ ##
+ # Generate:
+ #
+ # * a list of HtmlFile objects for each TopLevel object.
+ # * a list of HtmlClass objects for each first level
+ # class or module in the TopLevel objects
+ # * a complete list of all hyperlinkable terms (file,
+ # class, module, and method names)
+
+ def build_indices
+
+ @toplevels.each do |toplevel|
+ @files << HtmlFile.new(toplevel, @options, FILE_DIR)
+ end
+
+ RDoc::TopLevel.all_classes_and_modules.each do |cls|
+ build_class_list(cls, @files[0], CLASS_DIR)
+ end
+ end
+
+ def build_class_list(from, html_file, class_dir)
+ @classes << HtmlClass.new(from, html_file, class_dir, @options)
+ from.each_classmodule do |mod|
+ build_class_list(mod, html_file, class_dir)
+ end
+ end
+
+ ##
+ # Generate all the HTML
+ #
+ def generate_html
+ # the individual descriptions for files and classes
+ gen_into(@files)
+ gen_into(@classes)
+ # and the index files
+ gen_file_index
+ gen_class_index
+ gen_method_index
+ gen_main_index
+
+ # this method is defined in the template file
+ write_extra_pages if defined? write_extra_pages
+ end
+
+ def gen_into(list)
+ list.each do |item|
+ if item.document_self
+ op_file = item.path
+ File.makedirs(File.dirname(op_file))
+ File.open(op_file, "w") { |file| item.write_on(file) }
+ end
+ end
+
+ end
+
+ def gen_file_index
+ gen_an_index(@files, 'Files',
+ RDoc::Page::FILE_INDEX,
+ "fr_file_index.html")
+ end
+
+ def gen_class_index
+ gen_an_index(@classes, 'Classes',
+ RDoc::Page::CLASS_INDEX,
+ "fr_class_index.html")
+ end
+
+ def gen_method_index
+ gen_an_index(HtmlMethod.all_methods, 'Methods',
+ RDoc::Page::METHOD_INDEX,
+ "fr_method_index.html")
+ end
+
+
+ def gen_an_index(collection, title, template, filename)
+ template = TemplatePage.new(RDoc::Page::FR_INDEX_BODY, template)
+ res = []
+ collection.sort.each do |f|
+ if f.document_self
+ res << { "href" => f.path, "name" => f.name, "scope" => f.scope, "seq_id" => f.seq }
+ end
+ end
+
+ values = {
+ "entries" => res,
+ 'list_title' => CGI.escapeHTML(title),
+ 'index_url' => main_url,
+ 'charset' => @options.charset,
+ 'style_url' => style_url('', @options.css),
+ }
+
+ File.open(filename, "w") do |f|
+ template.write_html_on(f, values)
+ end
+ end
+
+ # The main index page is mostly a template frameset, but includes
+ # the initial page. If the --main option was given,
+ # we use this as our main page, otherwise we use the
+ # first file specified on the command line.
+
+ def gen_main_index
+ template = TemplatePage.new(RDoc::Page::INDEX)
+ File.open("index.html", "w") do |f|
+ tStr = ""
+ #File.open(main_url, 'r') do |g|
+ # tStr = markup(g)
+ #end
+ values = {
+ "initial_page" => tStr,
+ 'title' => CGI.escapeHTML(@options.title),
+ 'charset' => @options.charset,
+ 'content' => File.read('files/README.html')
+ }
+
+ values['inline_source'] = true
+ template.write_html_on(f, values)
+ end
+ end
+
+ # return the url of the main page
+ def main_url
+ "files/README.html"
+ end
+
+
+ end
+
+end
diff --git a/web/doc/rdoc/generators/template/merb/api_grease.js b/web/doc/rdoc/generators/template/merb/api_grease.js
new file mode 100644
index 000000000..3df710e8b
--- /dev/null
+++ b/web/doc/rdoc/generators/template/merb/api_grease.js
@@ -0,0 +1,640 @@
+
+function setupPage(){
+ hookUpActiveSearch();
+ hookUpTabs();
+ suppressPostbacks();
+ var url_params = getUrlParams();
+ if (url_params != null){
+ loadUrlParams(url_params);
+ }else{
+ loadDefaults();
+ }
+ resizeDivs();
+ window.onresize = function(){ resizeDivs(); };
+}
+
+function getUrlParams(){
+ var window_location = window.location.href
+ var param_pos = window_location.search(/\?/)
+ if (param_pos > 0){
+ return(window_location.slice(param_pos, window_location.length));
+ }else{
+ return(null);
+ }
+}
+
+function loadUrlParams(url_param){
+ //get the tabs
+ var t = getTabs();
+ // now find our variables
+ var s_params = /(\?)(a=.+?)(&)(name=.*)/;
+ var results = url_param.match(s_params);
+ url_anchor = results[2].replace(/a=/,'');
+
+ if (url_anchor.match(/M.+/)){//load the methods tab and scroller content
+ setActiveTabAndLoadContent(t[0]);
+ }else{
+ if(url_anchor.match(/C.+/)){ //load the classes tab and scroller content
+ setActiveTabAndLoadContent(t[1]);
+ }else{
+ if (url_anchor.match(/F.+/)){//load the files tab
+ setActiveTabAndLoadContent(t[2]);
+ }else{
+ // default to loading the methods
+ setActiveTabAndLoadContent(t[0]);
+ }
+ }
+ }
+ paramLoadOfContentAnchor(url_anchor + "_link");
+}
+
+function updateUrlParams(anchor_id, name){
+ //Also setting the page title
+ //window.document.title = name + " method - MerbBrain.com ";
+
+ //updating the window location
+ var current_href = window.location.href;
+ //var m_name = name.replace("?","?");
+ var rep_str = ".html?a=" + anchor_id + "&name=" + name;
+ var new_href = current_href.replace(/\.html.*/, rep_str);
+ if (new_href != current_href){
+ window.location.href = new_href;
+ }
+}
+
+//does as it says...
+function hookUpActiveSearch(){
+
+ var s_field = $('searchForm').getInputs('text')[0];
+ //var s_field = document.forms[0].searchText;
+ Event.observe(s_field, 'keydown', function(event) {
+ var el = Event.element(event);
+ var key = event.which || event.keyCode;
+
+ switch (key) {
+ case Event.KEY_RETURN:
+ forceLoadOfContentAnchor(getCurrentAnchor());
+ Event.stop(event);
+ break;
+
+ case Event.KEY_UP:
+ scrollListToElementOffset(getCurrentAnchor(),-1);
+ break;
+
+ case Event.KEY_DOWN:
+ scrollListToElementOffset(getCurrentAnchor(),1);
+ break;
+
+ default:
+ break;
+ }
+
+ });
+
+ Event.observe(s_field, 'keyup', function(event) {
+ var el = Event.element(event);
+ var key = event.which || event.keyCode;
+ switch (key) {
+ case Event.KEY_RETURN:
+ Event.stop(event);
+ break;
+
+ case Event.KEY_UP:
+ break;
+
+ case Event.KEY_DOWN:
+ break;
+
+ default:
+ scrollToName(el.value);
+ setSavedSearch(getCurrentTab(), el.value);
+ break;
+ }
+
+ });
+
+ Event.observe(s_field, 'keypress', function(event){
+ var el = Event.element(event);
+ var key = event.which || event.keyCode;
+ switch (key) {
+ case Event.KEY_RETURN:
+ Event.stop(event);
+ break;
+
+ default:
+ break;
+ }
+
+ });
+
+ //Event.observe(document, 'keypress', function(event){
+ // var key = event.which || event.keyCode;
+ // if (key == Event.KEY_TAB){
+ // cycleNextTab();
+ // Event.stop(event);
+ // }
+ //});
+}
+
+function hookUpTabs(){
+
+ var tabs = getTabs();
+ for(x=0; x < tabs.length; x++)
+ {
+ Event.observe(tabs[x], 'click', function(event){
+ var el = Event.element(event);
+ setActiveTabAndLoadContent(el);
+ });
+ //tabs[x].onclick = function (){ return setActiveTabAndLoadContent(this);}; //the prototype guys say this is bad..
+ }
+
+}
+
+function suppressPostbacks(){
+ Event.observe('searchForm', 'submit', function(event){
+ Event.stop(event);
+ });
+}
+
+function loadDefaults(){
+ var t = getTabs();
+ setActiveTabAndLoadContent(t[0]); //default loading of the first tab
+}
+
+function resizeDivs(){
+ var inner_height = 700;
+ if (window.innerHeight){
+ inner_height = window.innerHeight; //all browsers except IE use this to determine the space available inside a window. Thank you Microsoft!!
+ }else{
+ if(document.documentElement.clientHeight > 0){ //IE uses this in 'strict' mode
+ inner_height = document.documentElement.clientHeight;
+ }else{
+ inner_height = document.body.clientHeight; //IE uses this in 'quirks' mode
+ }
+ }
+ $('rdocContent').style.height = (inner_height - 92) + "px";//Thankfully all browsers can agree on how to set the height of a div
+ $('listScroller').style.height = (inner_height - 88) + "px";
+}
+
+//The main function for handling clicks on the tabs
+function setActiveTabAndLoadContent(current_tab){
+ changeLoadingStatus("on");
+ var tab_string = String(current_tab.innerHTML).strip(); //thank you ProtoType!
+ switch (tab_string){
+ case "classes":
+ setCurrentTab("classes");
+ loadScrollerContent('fr_class_index.html');
+ setSearchFieldValue(getSavedSearch("classes"));
+ scrollToName(getSavedSearch("classes"));
+ setSearchFocus();
+ break;
+
+ case "files":
+ setCurrentTab("files");
+ loadScrollerContent('fr_file_index.html');
+ setSearchFieldValue(getSavedSearch("files"));
+ scrollToName(getSavedSearch("files"));
+ setSearchFocus();
+ break;
+
+ case "methods":
+ setCurrentTab("methods");
+ loadScrollerContent('fr_method_index.html');
+ setSearchFieldValue(getSavedSearch("methods"));
+ scrollToName(getSavedSearch("methods"));
+ setSearchFocus();
+ break;
+
+ default:
+ break;
+ }
+ changeLoadingStatus("off");
+}
+
+function cycleNextTab(){
+ var currentT = getCurrentTab();
+ var tabs = getTabs();
+ if (currentT == "methods"){
+ setActiveTabAndLoadContent(tabs[1]);
+ setSearchFocus();
+ }else{
+ if (currentT == "classes"){
+ setActiveTabAndLoadContent(tabs[2]);
+ setSearchFocus();
+ }else{
+ if (currentT == "files"){
+ setActiveTabAndLoadContent(tabs[0]);
+ setSearchFocus();
+ }
+ }
+ }
+}
+
+function getTabs(){
+ return($('groupType').getElementsByTagName('li'));
+}
+
+var Active_Tab = "";
+function getCurrentTab(){
+ return Active_Tab;
+}
+
+function setCurrentTab(tab_name){
+ var tabs = getTabs();
+ for(x=0; x < tabs.length; x++)
+ {
+ if(tabs[x].innerHTML.strip() == tab_name) //W00t!!! String.prototype.strip!
+ {
+ tabs[x].className = "activeLi";
+ Active_Tab = tab_name;
+ }
+ else
+ {
+ tabs[x].className = "";
+ }
+ }
+}
+
+//These globals should not be used globally (hence the getters and setters)
+var File_Search = "";
+var Method_Search = "";
+var Class_Search = "";
+function setSavedSearch(tab_name, s_val){
+ switch(tab_name){
+ case "methods":
+ Method_Search = s_val;
+ break;
+ case "files":
+ File_Search = s_val;
+ break;
+ case "classes":
+ Class_Search = s_val;
+ break;
+ }
+}
+
+function getSavedSearch(tab_name){
+ switch(tab_name){
+ case "methods":
+ return (Method_Search);
+ break;
+ case "files":
+ return (File_Search);
+ break;
+ case "classes":
+ return (Class_Search);
+ break;
+ }
+}
+
+//These globals handle the history stack
+
+
+function setListScrollerContent(s){
+
+ $('listScroller').innerHTML = s;
+}
+
+function setMainContent(s){
+
+ $('rdocContent').innerHTML = s;
+}
+
+function setSearchFieldValue(s){
+
+ document.forms[0].searchText.value = s;
+}
+
+function getSearchFieldValue(){
+
+ return Form.Element.getValue('searchText');
+}
+
+function setSearchFocus(){
+
+ document.forms[0].searchText.focus();
+}
+
+var Anchor_ID_Of_Current = null; // holds the last highlighted anchor tag in the scroll lsit
+function getCurrentAnchor(){
+ return(Anchor_ID_Of_Current);
+}
+
+function setCurrentAnchor(a_id){
+ Anchor_ID_Of_Current = a_id;
+}
+
+//var Index_Of_Current = 0; //holds the last highlighted index
+//function getCurrentIndex(){
+// return (Index_Of_Current);
+//}
+
+//function setCurrentIndex(new_i){
+// Index_Of_Current = new_i;
+//}
+
+function loadScrollerContent(url){
+
+ var scrollerHtml = new Ajax.Request(url, {
+ asynchronous: false,
+ method: 'get',
+ onComplete: function(method_data) {
+ setListScrollerContent(method_data.responseText);
+ }
+ });
+
+}
+
+//called primarily from the links inside the scroller list
+//loads the main page div then jumps to the anchor/element with id
+function loadContent(url, anchor_id){
+
+ var mainHtml = new Ajax.Request(url, {
+ method: 'get',
+ onLoading: changeLoadingStatus("on"),
+ onSuccess: function(method_data) {
+ setMainContent(method_data.responseText);},
+ onComplete: function(request) {
+ changeLoadingStatus("off");
+ new jumpToAnchor(anchor_id);
+ }
+ });
+}
+
+//An alternative function that also will stuff the index history for methods, files, classes
+function loadIndexContent(url, anchor_id, name, scope)
+{
+ if (From_URL_Param == true){
+ var mainHtml = new Ajax.Request(url, {
+ method: 'get',
+ onLoading: changeLoadingStatus("on"),
+ onSuccess: function(method_data) {
+ setMainContent(method_data.responseText);},
+ onComplete: function(request) {
+ changeLoadingStatus("off");
+ updateBrowserBar(name, anchor_id, scope);
+ new jumpToAnchor(anchor_id);}
+ });
+ From_URL_Param = false;
+ }else{
+ updateUrlParams(anchor_id, name);
+ }
+
+}
+
+function updateBrowserBar(name, anchor_id, scope){
+ if (getCurrentTab() == "methods"){
+ $('browserBarInfo').update("class/module: " + scope + " method: " + name + " ");
+ }else{ if(getCurrentTab() == "classes"){
+ $('browserBarInfo').update("class/module: " + scope + "::" + name + " ");
+ }else{
+ $('browserBarInfo').update("file: " + scope + "/" + name + " ");
+ }
+ }
+}
+
+
+// Force loads the contents of the index of the current scroller list. It does this by
+// pulling the onclick method out and executing it manually.
+function forceLoadOfContent(index_to_load){
+ var scroller = $('listScroller');
+ var a_array = scroller.getElementsByTagName('a');
+ if ((index_to_load >= 0) && (index_to_load < a_array.length)){
+ var load_element = a_array[index_to_load];
+ var el_text = load_element.innerHTML.strip();
+ setSearchFieldValue(el_text);
+ setSavedSearch(getCurrentTab(), el_text);
+ eval("new " + load_element.onclick);
+ }
+}
+
+function forceLoadOfContentAnchor(anchor_id){
+
+ var load_element = $(anchor_id);
+ if (load_element != null){
+ var el_text = load_element.innerHTML.strip();
+ setSearchFieldValue(el_text);
+ scrollToAnchor(anchor_id);
+ setSavedSearch(getCurrentTab(), el_text);
+ eval("new " + load_element.onclick);
+ }
+}
+
+var From_URL_Param = false;
+function paramLoadOfContentAnchor(anchor_id){
+ From_URL_Param = true;
+ forceLoadOfContentAnchor(anchor_id);
+}
+
+//this handles the up/down keystrokes to move the selection of items in the list
+function scrollListToElementOffset(anchor_id, offset){
+ var scroller = $('listScroller');
+ var a_array = scroller.getElementsByTagName('a');
+ var current_index = findIndexOfAnchor(a_array, anchor_id);
+ if ((current_index >= 0) && (current_index < a_array.length)){
+ scrollListToAnchor(a_array[current_index + offset].id);
+ setListActiveAnchor(a_array[current_index + offset].id);
+ }
+}
+
+function findIndexOfAnchor(a_array, anchor_id){
+ var found=false;
+ var counter = 0;
+ while(!found && counter < a_array.length){
+ if (a_array[counter].id == anchor_id){
+ found = true;
+ }else{
+ counter +=1;
+ }
+ }
+ return(counter);
+}
+
+function scrollToName(searcher_name){
+
+ var scroller = $('listScroller');
+ var a_array = scroller.getElementsByTagName('a');
+
+ if (!searcher_name.match(new RegExp(/\s+/))){ //if searcher name is blank
+
+ var searcher_pattern = new RegExp("^"+searcher_name, "i"); //the "i" is for case INsensitive
+ var found_index = -1;
+
+ var found = false;
+ var x = 0;
+ while(!found && x < a_array.length){
+ if(a_array[x].innerHTML.match(searcher_pattern)){
+ found = true;
+ found_index = x;
+ }
+ else{
+ x++;
+ }
+ }
+
+ // // an attempt at binary searching... have not given up on this yet...
+ //found_index = binSearcher(searcher_pattern, a_array, 0, a_array.length);
+
+ if ((found_index >= 0) && (found_index < a_array.length)){
+
+ scrollListToAnchor(a_array[found_index].id);//scroll to the item
+ setListActiveAnchor(a_array[found_index].id);//highlight the item
+ }
+ }else{ //since searcher name is blank
+ //scrollListToIndex(a_array, 0);//scroll to the item
+ //setListActiveItem(a_array, 0);//highlight the item
+ }
+}
+
+function scrollToAnchor(anchor_id){
+ var scroller = $('listScroller');
+ if ($(anchor_id) != null){
+ scrollListToAnchor(anchor_id);
+ setListActiveAnchor(anchor_id);
+ }
+}
+
+function getY(element){
+
+ var y = 0;
+ for( var e = element; e; e = e.offsetParent)//iterate the offset Parents
+ {
+ y += e.offsetTop; //add up the offsetTop values
+ }
+ //for( e = element.parentNode; e && e != document.body; e = e.parentNode)
+ // if (e.scrollTop) y -= e.scrollTop; //subtract scrollbar values
+ return y;
+}
+
+//function setListActiveItem(item_array, active_index){
+//
+// item_array[getCurrentIndex()].className = "";
+// setCurrentIndex(active_index);
+// item_array[getCurrentIndex()].className = "activeA"; //setting the active class name
+//}
+
+function setListActiveAnchor(active_anchor){
+ if ((getCurrentAnchor() != null) && ($(getCurrentAnchor()) != null)){
+ $(getCurrentAnchor()).className = "";
+ }
+ setCurrentAnchor(active_anchor);
+ $(getCurrentAnchor()).className = "activeA";
+
+}
+
+//handles the scrolling of the list and setting of the current index
+//function scrollListToIndex(a_array, scroll_index){
+// if (scroll_index > 0){
+// var scroller = $('listScroller');
+// scroller.scrollTop = getY(a_array[scroll_index]) - 120; //the -120 is what keeps it from going to the top...
+// }
+//}
+
+function scrollListToAnchor(scroll2_anchor){
+ var scroller = $('listScroller');
+ scroller.scrollTop = getY($(scroll2_anchor)) - 120;
+}
+
+function jumpToAnchor(anchor_id){
+
+ var contentScroller = $('rdocContent');
+ var a_div = $(anchor_id);
+ contentScroller.scrollTop = getY(a_div) - 80; //80 is the offset to adjust scroll point
+ var a_title = $(anchor_id + "_title");
+ a_title.style.backgroundColor = "#222";
+ a_title.style.color = "#FFF";
+ a_title.style.padding = "3px";
+ // a_title.style.borderBottom = "2px solid #ccc";
+
+ //other attempts
+ //a_div.className = "activeMethod"; //setting the active class name
+ //a_div.style.backgroundColor = "#ffc";
+ //var titles = a_div.getElementsByClassName("title");
+ //titles[0].className = "activeTitle";
+
+}
+
+function jumpToTop(){
+ $('rdocContent').scrollTop = 0;
+}
+
+function changeLoadingStatus(status){
+ if (status == "on"){
+ $('loadingStatus').show();
+ }
+ else{
+ $('loadingStatus').hide();
+ }
+}
+
+//************* Misc functions (mostly from the old rdocs) ***********************
+//snagged code from the old templating system
+function toggleSource( id ){
+
+ var elem
+ var link
+
+ if( document.getElementById )
+ {
+ elem = document.getElementById( id )
+ link = document.getElementById( "l_" + id )
+ }
+ else if ( document.all )
+ {
+ elem = eval( "document.all." + id )
+ link = eval( "document.all.l_" + id )
+ }
+ else
+ return false;
+
+ if( elem.style.display == "block" )
+ {
+ elem.style.display = "none"
+ link.innerHTML = "show source"
+ }
+ else
+ {
+ elem.style.display = "block"
+ link.innerHTML = "hide source"
+ }
+}
+
+function openCode( url ){
+ window.open( url, "SOURCE_CODE", "width=400,height=400,scrollbars=yes" )
+}
+
+//this function handles the ajax calling and afterits loaded the jumping to the anchor...
+function jsHref(url){
+ //alert(url);
+ var mainHtml = new Ajax.Request(url, {
+ method: 'get',
+ onSuccess: function(method_data) {
+ setMainContent(method_data.responseText);}
+ });
+}
+
+//function comparePatterns(string, regexp){
+// var direction = 0;
+//
+//
+// return (direction)
+//}
+
+////returns the index of the element
+//function binSearcher(regexp_pattern, list, start_index, stop_index){
+// //divide the list in half
+// var split_point = 0;
+// split_point = parseInt((stop_index - start_index)/2);
+// direction = comparePatterns(list[split_point].innerHTML, regexp_pattern);
+// if(direction < 0)
+// return (binSearcher(regexp_pattern, list, start_index, split_point));
+// else
+// if(direction > 0)
+// return (binSearcher(regexp_pattern, list, split_point, stop_index));
+// else
+// return(split_point);
+//
+//}
+
+
+
diff --git a/web/doc/rdoc/generators/template/merb/index.html.erb b/web/doc/rdoc/generators/template/merb/index.html.erb
new file mode 100644
index 000000000..5c8e79867
--- /dev/null
+++ b/web/doc/rdoc/generators/template/merb/index.html.erb
@@ -0,0 +1,37 @@
+
+
+
+ Documentation
+
+
+
+
+
+
+
+
+
+
+
diff --git a/web/doc/rdoc/generators/template/merb/merb.css b/web/doc/rdoc/generators/template/merb/merb.css
new file mode 100644
index 000000000..e4f5531b8
--- /dev/null
+++ b/web/doc/rdoc/generators/template/merb/merb.css
@@ -0,0 +1,252 @@
+html, body, div, span, applet, object, iframe,h1, h2, h3, h4, h5, h6, p, blockquote, pre,a, abbr, acronym, address, big, cite, code,del, dfn, em, font, img, ins, kbd, q, s, samp,small, strike, strong, sub, sup, tt, var,dl, dt, dd, ol, ul, li,fieldset, form, label, legend,table, caption, tbody, tfoot, thead, tr, th, td {
+ margin: 0;
+ padding: 0;
+ border: 0;
+ font-weight: inherit;
+ font-style: inherit;
+ font-size: 100%;
+ font-family: inherit;
+ vertical-align: baseline; }
+
+/* GENERAL RULES */
+
+body {
+ background: #000 url(../img/body.gif) repeat-x bottom center;
+ color: #000;
+ font: normal 12px "Lucida Grande", "Arial", sans-serif;
+ line-height: 1;
+}
+ul {list-style-type: none;}
+#content_full ul.revisions{list-style-type: disc;}
+#content_full ul.revisions li{margin-left: 15px;padding: 3px 0;}
+li a {display: block;}
+#content_full ul.revisions li a{display: inline;}
+strong {font-weight: bold;}
+table {border-collapse: separate;border-spacing: 0; }
+caption, th, td {text-align: left;font-weight: normal; }
+.invisible {display: none;}
+.full_width {width:100%;}
+
+/* LAYOUT */
+
+.wrap_to_center, #foot {
+ margin: 0 auto;
+ display: block;
+ width: 800px;
+}
+
+#content {width: 100%;}
+
+#content_top {
+ background: #fff url(../img/content_top.gif) no-repeat top center;
+ float:left;
+ margin:25px 0px;
+ width:100%;
+}
+#content_bottom {
+ background: url(../img/content_bottom.gif) no-repeat bottom center;
+ width:100%;
+ float:left;
+}
+#content_main {
+ float:left;
+ margin: 10px 20px 20px 20px;
+ width:506px;
+}
+#content p {
+ line-height:17px;
+}
+#content_full {margin: 10px 20px 20px 20px;}
+
+/* HEADER & NAVIGATION */
+
+#header {
+ background: #1db900 url(../img/header_waves.gif) repeat-x top center;
+ height:74px;
+ width: 100%;
+}
+#waves {
+ background: url(../img/header_waves.gif)no-repeat top left;
+ height:74px;
+ width:980px;
+}
+#header img {margin-top:8px; float:left;}
+#header a {color:#fff; text-decoration:none;}
+#header a:hover {color:#000;}
+ul#nav {float:right;display:block;width:43.3em;margin-top:25px;}
+ul#nav li {display:block;float:left;}
+ul#nav li a {display:block;float:left;margin:0px 5px;padding:6px 9px 31px 9px;}
+ul#nav li a:hover {background:url(../img/header_hover.gif) repeat-x bottom center;}
+ul#nav li a#active {background:url(../img/header_arrow.gif)no-repeat bottom center;}
+ul#nav li.last a {margin-right:0;}
+
+/* TEXT FORMATTING */
+
+h1 {
+ border-bottom:2px solid #ccc;
+ color:#000;
+ font:bold 28px "Arial" sans-serif;
+ letter-spacing:1px;
+ margin:20px 0px;
+ text-align:left;
+ width:100%;
+}
+h1.home {
+ border:0;
+ color:#fff;
+ font-size:36px;
+ margin:20px 0px;
+ text-align:center;
+}
+h2 {
+ color:#7aad00;
+ font:bold 22px "Lucida Grande" sans-serif;
+ margin:10px 0px;
+}
+h3 {
+ font:bold 16px "Lucida Grande";
+ margin:10px 0px;
+}
+#content a {color:#d7ff00;}
+#content a:hover {background:#d7ff00;color:#000;}
+#content_main ul {margin:10px 0px;}
+#content_main ul li {
+ background: url(../img/li.gif) no-repeat left center;
+ padding: 4px 4px 4px 16px;
+ font-weight:bold;
+}
+p {margin-bottom:12px;}
+#content_main a,#content_full a {color:#11b716;font-weight:bold;}
+#content_main a:hover,#content_full a:hover {background:#22d716;}
+pre {
+ background:#222;
+ color:#fff;
+ font:12px "Courier" serif;
+ line-height:18px;
+ padding: 12px;
+ margin-bottom: 10px;
+}
+code {
+ font:bold 12px "Courier" serif;
+}
+pre code {font-weight:normal;}
+
+/* SIDEBAR FOR CONTENT */
+
+#content_sidebar {
+ float: left;
+ margin: 20px 20px 15px 10px;
+ width: 224px;
+}
+.sidebar_top {
+ background:#868686 url(../img/sidebar_top.gif) no-repeat top center;
+ margin-bottom:12px;
+ width:224px;
+}
+dl.sidebar_bottom {
+ background: url(../img/sidebar_bottom.gif) no-repeat bottom center;
+ padding:12px;
+}
+dl.sidebar_bottom dt {
+ color:#fff;
+ font:bold 14px "Lucida Grande" sans-serif;
+ margin-bottom:6px;
+}
+dl.sidebar_bottom dd {padding:3px 0px;}
+#content_sidebar p {padding:10px 0px;}
+p#rss a {
+ background: url(../img/rss.gif) no-repeat left center;
+ color:#000;
+ font:bold 14px "Lucida Grande";
+ padding: 8px 6px 8px 34px;
+ text-decoration:none;
+}
+p#rss a:hover {
+ background: url(../img/rss.gif) no-repeat left center;
+ background-color:#fff;
+ text-decoration:underline;
+}
+
+/* FOOTER */
+
+#footer {background:#444; clear:both;}
+#footer p {padding:12px; color:#999; margin:0; text-align:center;}
+
+/* FEATURES PAGE */
+.feature {
+ background-repeat:no-repeat;
+ background-position:top left;
+ border-bottom:2px solid #ccc;
+ padding-left:150px;
+}
+div#speed {background-image: url(../img/feature_speed.gif);}
+div#light {background-image: url(../img/feature_light.gif);}
+div#power {background-image: url(../img/feature_power.gif);}
+
+.quicklinks_top {
+ background:#868686 url(../img/quicklinks_top.gif) no-repeat top center;
+ float:right;
+ margin-bottom:12px;
+ width:169px;
+}
+ul.quicklinks_bottom {
+ background: url(../img/quicklinks_bottom.gif) no-repeat bottom center;
+ padding:12px;
+}
+ul.quicklinks_bottom li {
+ display:block;
+ padding:3px 0px;
+}
+#content_full ul.quicklinks_bottom li a{
+ color:#d7ff00;
+ display:inline;
+}
+#content_full ul.quicklinks_bottom li a:hover {
+ background:#d7ff00;
+ color:#000;
+}
+
+/* DOCUMENTATION PAGE */
+.sub-framework {
+ border-bottom:2px solid #ccc;
+ margin-bottom: 20px;
+ padding-bottom: 10px;
+}
+
+
+/* ICONS FOR HOMEPAGE */
+
+#icons_top {
+ background: url(../img/icons_top.gif) no-repeat top center;
+ float:left;
+ width:800px;
+}
+#icons_bottom {
+ background: url(../img/icons_bottom.gif) no-repeat bottom center;
+ float:left;
+ width:800px;
+}
+#icons_top dl {
+ color:#fff;
+ float:left;
+ width: 224px;
+ padding: 15px 20px;
+}
+#icons_top dt {
+ background-repeat:no-repeat;
+ background-position:center 2.5em;
+ color:#35d726;
+ font:bold 18px 'Lucida Grande' sans-serif;
+ padding: 6px 6px 150px 6px;
+ text-align:center;
+}
+#icons_top dd {
+ font: 11px "Lucida Grande";
+ line-height:18px;
+ text-align:center;
+}
+dl#speed, dl#light {border-right:1px solid #444;}
+dl#light, dl#power {border-left:1px solid #000;}
+dl#speed dt {background-image: url(../img/icon_speed.gif);}
+dl#light dt {background-image: url(../img/icon_light.gif);}
+dl#power dt {background-image: url(../img/icon_power.gif);}
\ No newline at end of file
diff --git a/web/doc/rdoc/generators/template/merb/merb.rb b/web/doc/rdoc/generators/template/merb/merb.rb
new file mode 100644
index 000000000..36a77ed31
--- /dev/null
+++ b/web/doc/rdoc/generators/template/merb/merb.rb
@@ -0,0 +1,351 @@
+module RDoc
+module Page
+
+STYLE = File.read(File.join(File.dirname(__FILE__), 'merb_doc_styles.css'))
+FONTS = ""
+
+###################################################################
+
+CLASS_PAGE = <
+
+HTML
+
+###################################################################
+
+METHOD_LIST = <
+IF:diagram
+
+ENDIF:diagram
+
+IF:description
+ %description%
+ENDIF:description
+
+IF:requires
+ Required Files
+
+START:requires
+ %name%
+END:requires
+
+ENDIF:requires
+
+IF:toc
+ Contents
+
+ENDIF:toc
+
+IF:methods
+ Methods
+
+START:methods
+ %name%
+END:methods
+
+ENDIF:methods
+
+IF:includes
+Included Modules
+
+START:includes
+ %name%
+END:includes
+
+ENDIF:includes
+
+START:sections
+IF:sectitle
+
+IF:seccomment
+
+%seccomment%
+
+ENDIF:seccomment
+ENDIF:sectitle
+
+IF:classlist
+ Classes and Modules
+ %classlist%
+ENDIF:classlist
+
+IF:constants
+ Constants
+
+START:constants
+
+ %name%
+ =
+ %value%
+
+IF:desc
+
+
+ %desc%
+
+ENDIF:desc
+END:constants
+
+ENDIF:constants
+
+IF:attributes
+ Attributes
+
+START:attributes
+
+
+IF:rw
+[%rw%]
+ENDIF:rw
+
+ %name%
+ %a_desc%
+
+END:attributes
+
+ENDIF:attributes
+
+IF:method_list
+START:method_list
+IF:methods
+%type% %category% methods
+START:methods
+
+
+IF:callseq
+
%callseq%
+ENDIF:callseq
+IFNOT:callseq
+
%name% %params%
+ENDIF:callseq
+IF:codeurl
+[
source ]
+ENDIF:codeurl
+
+IF:m_desc
+
+ %m_desc%
+
+ENDIF:m_desc
+IF:aka
+
+ This method is also aliased as
+START:aka
+
%name%
+END:aka
+
+ENDIF:aka
+IF:sourcecode
+
+ENDIF:sourcecode
+
+END:methods
+ENDIF:methods
+END:method_list
+ENDIF:method_list
+END:sections
+
+HTML
+
+
+
+
+BODY = <
+
+
+ #{METHOD_LIST}
+
+
+ENDBODY
+
+
+
+SRC_BODY = <
+
+
+
Source Code
+
%file_source_code%
+
+ENDSRCBODY
+
+
+###################### File Page ##########################
+FILE_PAGE = <
+ %short_name%
+
+
+HTML
+
+
+#### This is not used but kept for historical purposes
+########################## Source code ##########################
+# Separate page onlye
+
+SRC_PAGE = <
+%title%
+
+
+
+
+%code%
+
+
+HTML
+
+########################### source page body ###################
+
+SCR_CODE_BODY = <
+ %source_code%
+
+
+HTML
+
+########################## Index ################################
+
+FR_INDEX_BODY = <
+START:entries
+%name% %scope%
+END:entries
+
+HTML
+
+CLASS_INDEX = FILE_INDEX
+METHOD_INDEX = FILE_INDEX
+
+INDEX = <
+
+
+
+
+
+
+
+ Merb | %title% API Documentation
+
+
+
+
+
+
+ methods
+ classes
+ files
+ loading...
+
+
+
+
+
+
+ Loading via ajax... this could take a sec.
+
+
+
+ %title% README
+
+
+ %content%
+
+
+
Documentation for %title% usage tips
+
+
Some tips
+
+ Up/Down keys move through the search list
+ Return/enter key loads selected item
+ Want to use this RDOC template for your own project? Check out http://rubyforge.org/projects/jaxdoc
+
+
+
+
+
+
+
+
+HTML
+
+API_GREASE_JS = File.read(File.join(File.dirname(__FILE__), 'api_grease.js'))
+
+PROTOTYPE_JS = File.read(File.join(File.dirname(__FILE__), 'prototype.js'))
+end
+end
+
diff --git a/web/doc/rdoc/generators/template/merb/merb_doc_styles.css b/web/doc/rdoc/generators/template/merb/merb_doc_styles.css
new file mode 100644
index 000000000..cb01bb732
--- /dev/null
+++ b/web/doc/rdoc/generators/template/merb/merb_doc_styles.css
@@ -0,0 +1,492 @@
+html, body {
+ padding:10px 0px 0px 5px;
+ margin: 0px;
+ font-family: "Lucida Grande", "Lucida Sans Unicode", sans-serif;
+ font-size: 14px;
+}
+
+body {
+ background: #000000 url(http://merbivore.com/img/header_waves.gif) repeat-x scroll center top;
+}
+
+td, p {
+ background: #FFF;
+ color: #000;
+ margin: 0px;
+ font-size: small;
+ line-height: 17px;
+ margin-bottom 12px;
+}
+
+#floater {
+ position: absolute;
+ top: 5px;
+ right: 5px;
+}
+
+#floater strong {
+ color: white;
+}
+
+#floater a {
+ color: black;
+}
+
+#floater a:hover {
+ background-color: transparent;
+}
+
+
+/*holds the whole searching/drill down stuff */
+#listFrame{
+ float:left;
+ padding: 2px;
+ width: 350px;
+ background-color: #868686;
+ border: 1px solid #999;
+ border-right: none;
+}
+
+#browserBar{
+ height: 25px;
+ padding:11px 0px 0px 0px;
+ margin:0px;
+ background-color: #868686;
+ border-top: 1px solid #999;
+ color: white;
+}
+
+#browserBar a{
+ text-decoration: none;
+}
+
+.button{
+ text-decoration: none;
+ padding:3px 8px 3px 8px;
+ border: 1px solid #66a;
+ background-color: #ccf;
+ color: #66a;
+}
+
+.buttonInactive{
+ text-decoration: none;
+ padding:3px 8px 3px 8px;
+ border: 1px solid #999;
+ background-color: #ccc;
+ color: #999;
+}
+
+.miniButton{
+ text-decoration: none;
+ padding:3px 2px 3px 2px;
+ border: 1px solid #66a;
+ background-color: #ccf;
+ color: #66a;
+}
+
+.miniButtonInactive{
+ text-decoration: none;
+ padding:3px 2px 3px 2px;
+ border: 1px solid #999;
+ background-color: #ccc;
+ color: #999;
+}
+
+#blowOutListBox{
+ position: absolute;
+ top: 63px;
+ left: 399px;
+ border: 1px solid #999;
+ padding: 0px;
+ margin: 0px;
+ z-index: 1000;
+ background-color: #ccf;
+ color: #66a;
+}
+
+#blowOutListBox ul{
+ list-style-type:none;
+ padding: 0px;
+ margin: 0px;
+}
+
+#blowOutListBox ul li{
+ padding: 3px;
+ margin: 0px;
+ line-height: 1.1em;
+
+}
+
+#blowOutListBox ul li a{
+ text-decoration: none;
+ padding: 3px;
+}
+#blowOutListBox ul li a:hover{
+ background-color: #ddf;
+}
+
+/*holds the content for browsing etc... also is the target of method/class/file name clicks */
+#rdocContent{
+ height: 600px;
+ background-color: #fff;
+ border: 1px solid #999;
+ border-left: 0px;
+ padding:5px;
+ overflow: auto;
+}
+
+/*the grouping for methods,files,class,all... i.e. the tabs */
+ul#groupType{
+ list-style-type: none;
+ padding: 0px;
+ padding-left: 5px;
+ margin: 0px;
+}
+
+ul#groupType li{
+ color: white;
+ display:inline;
+ padding: 5px 5px 0px 5px;
+ cursor: pointer;
+}
+
+ul#groupType li#loadingStatus{
+ margin: 3px;
+ border: 0px;
+ padding: 3px 3px 6px 3px;
+ color: #666;
+}
+
+ul#groupType li.activeLi{
+ border: 1px solid #999;
+ border-bottom: 0px;
+ background-color: #868686;
+ font-weight: bold;
+ padding-bottom: 1px;
+}
+
+#listSearch{
+ height: 25px;
+ padding: 3px;
+}
+
+#listSearch input[type=text]{
+ width: 340px;
+ font-size: 1.2em;
+}
+
+#listScroller{
+ width: 342px;
+ height: 700px;
+ margin: 3px;
+ background-color: #fcfcfc;
+ border: 1px solid #999;
+ overflow: auto;
+}
+
+#listScroller ul{
+ width: 500px;
+ padding:0px;
+ margin:0px;
+ list-style: none;
+}
+
+#listScroller li{
+ padding: 0px;
+ margin: 0px;
+ display: block;
+ line-height: 1.1em;
+}
+
+a, h1 a, h2 a, .sectiontitle a, #listScroller a{
+ color: #11B716;
+ font-weight: bold;
+ text-decoration: none;
+ padding: 0px 1px 1px 1px;
+ margin: 3px;
+ font-weight: bold;
+}
+
+a:hover, h1 a:hover, h2 a:hover, .sectiontitle a:hover, #listScroller a:hover{
+ background-color: #22D716;
+ color: black;
+}
+
+#browserBar a, .banner a {
+ color: #D7FF00;
+}
+
+#browserBar a:hover, .banner a:hover {
+ background-color: #D7FF00;
+ color: #000;
+}
+
+#listScroller a.activeA {
+ background-color: #22D716;
+ color: black ;
+ border: 1px solid #ccc;
+ padding: 0px 1px 1px 1px;
+}
+
+#listScroller small{
+ color: #999;
+}
+
+.activeTitle{
+ font-family: monospace;
+ font-size: large;
+ border-bottom: 1px dashed black;
+ margin-bottom: 0.3em;
+ padding-bottom: 0.1em;
+ background-color: #ffc;
+}
+
+.activeMethod{
+ margin-left: 1em;
+ margin-right: 1em;
+ margin-bottom: 1em;
+}
+
+
+.activeMethod .title {
+ font-family: monospace;
+ font-size: large;
+ border-bottom: 1px dashed black;
+ margin-bottom: 0.3em;
+ padding-bottom: 0.1em;
+ background-color: #ffa;
+}
+
+.activeMethod .description, .activeMethod .sourcecode {
+ margin-left: 1em;
+}
+
+.activeMethod .sourcecode p.source-link {
+ text-indent: 0em;
+ margin-top: 0.5em;
+}
+
+.activeMethod .aka {
+ margin-top: 0.3em;
+ margin-left: 1em;
+ font-style: italic;
+ text-indent: 2em;
+}
+
+#content {
+ margin: 0.5em;
+}
+
+#description p {
+ margin-bottom: 0.5em;
+}
+
+.sectiontitle {
+ color: black;
+ font-size: 28px;
+ margin: 20px 0px;
+ border-bottom: 2px solid #CCCCCC;
+
+/* margin-top: 1em;
+ margin-bottom: 1em;
+ padding: 0.5em;
+ padding-left: 2em;
+ background: #005;
+ color: #FFF;
+ font-weight: bold;
+ border: 1px dotted black;*/
+}
+
+.attr-rw {
+ padding-left: 1em;
+ padding-right: 1em;
+ text-align: center;
+ color: #7AAD00;
+}
+
+.attr-name {
+ font-weight: bold;
+}
+
+.attr-desc {
+}
+
+.attr-value {
+ font-family: monospace;
+}
+
+.file-title-prefix {
+ font-size: large;
+}
+
+.file-title {
+ font-size: large;
+ font-weight: bold;
+ background: #005;
+ color: #FFF;
+}
+
+.banner {
+ background: #888;
+ color: #FFF;
+/* border: 1px solid black;*/
+ padding: 1em;
+}
+
+.banner td {
+ background: transparent;
+ color: #FFF;
+}
+
+.dyn-source {
+ display: none;
+ color: #000;
+ border: 0px;
+ border-left: 1px dotted #CCC;
+ border-top: 1px dotted #CCC;
+ margin: 0em;
+ padding: 0em;
+}
+
+.dyn-source .cmt {
+ color: #7AAD00;
+ font-style: italic;
+}
+
+.dyn-source .kw {
+ color: #11B716;
+ font-weight: bold;
+}
+
+.method {
+ margin-left: 1em;
+ margin-right: 1em;
+ margin-bottom: 2em;
+}
+
+.description pre, .description td {
+ font-family:"Courier",serif;
+}
+pre, .description pre {
+ font-size: 12px;
+ line-height: 18px;
+ color: white;
+ padding: 12px;
+ background: #222;
+ overflow: auto;
+}
+
+h2.title, .method .title {
+ color: #7AAD00;
+ font-size: 22px;
+ margin: 10px 0px;
+
+/* font-size: large;
+ border-bottom: 1px dashed black;
+ margin: 0.3em;
+ padding: 0.2em;
+*/}
+
+.method .description, .method .sourcecode {
+ margin-left: 1em;
+}
+
+.description p, .sourcecode p {
+ margin-bottom: 0.5em;
+}
+
+.method .sourcecode p.source-link {
+ text-indent: 0em;
+ margin-top: 0.5em;
+}
+
+.method .aka {
+ margin-top: 0.3em;
+ margin-left: 1em;
+ font-style: italic;
+ text-indent: 2em;
+}
+
+h1 {
+ padding: 1em;
+ font-size: x-large;
+}
+
+h2 {
+ padding: 0.5em 1em 0.5em 1em;
+ font-size: large;
+}
+
+
+h1, h2, h3, h4, h5, h6 {
+ color: white;
+ background-color: #868686;
+}
+
+h3, h4, h5, h6 {
+ padding: 0.2em 1em 0.2em 1em;
+ font-weight: bold;
+}
+
+h4 {
+ margin-bottom: 2px;
+}
+
+.sourcecode > pre {
+ padding: 0px;
+ margin: 0px;
+ border: 1px dotted black;
+ background: #FFE;
+}
+
+/* ============= */
+/* = home page = */
+/* ============= */
+
+body#home {
+ margin: 0;
+ padding: 0;
+}
+
+#content {
+ margin: 0 auto;
+ width: 800px;
+}
+
+#content h1.home {
+ background-color: transparent;
+ border:0pt none;
+ color:#FFFFFF;
+ font-size:36px;
+ margin:20px 0px;
+ padding: 0;
+ text-align:center;
+}
+
+#content #documentation-links h2.title {
+ background-color: transparent;
+}
+
+#documentation-links {
+ background-color : white;
+ margin-bottom: 20px;
+ padding-bottom: 10px;
+}
+
+#documentation-links p {
+ margin: 22px;
+}
+
+body#home #footer {
+ background:#444444 none repeat scroll 0%;
+ clear:both;
+}
+
+#footer p {
+ background-color: transparent;
+ color:#999999;
+ margin:0 auto;
+ padding:12px;
+ text-align:center;
+ width: 800px;
+}
\ No newline at end of file
diff --git a/web/doc/rdoc/generators/template/merb/prototype.js b/web/doc/rdoc/generators/template/merb/prototype.js
new file mode 100644
index 000000000..505822177
--- /dev/null
+++ b/web/doc/rdoc/generators/template/merb/prototype.js
@@ -0,0 +1,2515 @@
+/* Prototype JavaScript framework, version 1.5.0
+ * (c) 2005-2007 Sam Stephenson
+ *
+ * Prototype is freely distributable under the terms of an MIT-style license.
+ * For details, see the Prototype web site: http://prototype.conio.net/
+ *
+/*--------------------------------------------------------------------------*/
+
+var Prototype = {
+ Version: '1.5.0',
+ BrowserFeatures: {
+ XPath: !!document.evaluate
+ },
+
+ ScriptFragment: '(?:
)((\n|\r|.)*?)(?:<\/script>)',
+ emptyFunction: function() {},
+ K: function(x) { return x }
+}
+
+var Class = {
+ create: function() {
+ return function() {
+ this.initialize.apply(this, arguments);
+ }
+ }
+}
+
+var Abstract = new Object();
+
+Object.extend = function(destination, source) {
+ for (var property in source) {
+ destination[property] = source[property];
+ }
+ return destination;
+}
+
+Object.extend(Object, {
+ inspect: function(object) {
+ try {
+ if (object === undefined) return 'undefined';
+ if (object === null) return 'null';
+ return object.inspect ? object.inspect() : object.toString();
+ } catch (e) {
+ if (e instanceof RangeError) return '...';
+ throw e;
+ }
+ },
+
+ keys: function(object) {
+ var keys = [];
+ for (var property in object)
+ keys.push(property);
+ return keys;
+ },
+
+ values: function(object) {
+ var values = [];
+ for (var property in object)
+ values.push(object[property]);
+ return values;
+ },
+
+ clone: function(object) {
+ return Object.extend({}, object);
+ }
+});
+
+Function.prototype.bind = function() {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function() {
+ return __method.apply(object, args.concat($A(arguments)));
+ }
+}
+
+Function.prototype.bindAsEventListener = function(object) {
+ var __method = this, args = $A(arguments), object = args.shift();
+ return function(event) {
+ return __method.apply(object, [( event || window.event)].concat(args).concat($A(arguments)));
+ }
+}
+
+Object.extend(Number.prototype, {
+ toColorPart: function() {
+ var digits = this.toString(16);
+ if (this < 16) return '0' + digits;
+ return digits;
+ },
+
+ succ: function() {
+ return this + 1;
+ },
+
+ times: function(iterator) {
+ $R(0, this, true).each(iterator);
+ return this;
+ }
+});
+
+var Try = {
+ these: function() {
+ var returnValue;
+
+ for (var i = 0, length = arguments.length; i < length; i++) {
+ var lambda = arguments[i];
+ try {
+ returnValue = lambda();
+ break;
+ } catch (e) {}
+ }
+
+ return returnValue;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+var PeriodicalExecuter = Class.create();
+PeriodicalExecuter.prototype = {
+ initialize: function(callback, frequency) {
+ this.callback = callback;
+ this.frequency = frequency;
+ this.currentlyExecuting = false;
+
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ this.timer = setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ stop: function() {
+ if (!this.timer) return;
+ clearInterval(this.timer);
+ this.timer = null;
+ },
+
+ onTimerEvent: function() {
+ if (!this.currentlyExecuting) {
+ try {
+ this.currentlyExecuting = true;
+ this.callback(this);
+ } finally {
+ this.currentlyExecuting = false;
+ }
+ }
+ }
+}
+String.interpret = function(value){
+ return value == null ? '' : String(value);
+}
+
+Object.extend(String.prototype, {
+ gsub: function(pattern, replacement) {
+ var result = '', source = this, match;
+ replacement = arguments.callee.prepareReplacement(replacement);
+
+ while (source.length > 0) {
+ if (match = source.match(pattern)) {
+ result += source.slice(0, match.index);
+ result += String.interpret(replacement(match));
+ source = source.slice(match.index + match[0].length);
+ } else {
+ result += source, source = '';
+ }
+ }
+ return result;
+ },
+
+ sub: function(pattern, replacement, count) {
+ replacement = this.gsub.prepareReplacement(replacement);
+ count = count === undefined ? 1 : count;
+
+ return this.gsub(pattern, function(match) {
+ if (--count < 0) return match[0];
+ return replacement(match);
+ });
+ },
+
+ scan: function(pattern, iterator) {
+ this.gsub(pattern, iterator);
+ return this;
+ },
+
+ truncate: function(length, truncation) {
+ length = length || 30;
+ truncation = truncation === undefined ? '...' : truncation;
+ return this.length > length ?
+ this.slice(0, length - truncation.length) + truncation : this;
+ },
+
+ strip: function() {
+ return this.replace(/^\s+/, '').replace(/\s+$/, '');
+ },
+
+ stripTags: function() {
+ return this.replace(/<\/?[^>]+>/gi, '');
+ },
+
+ stripScripts: function() {
+ return this.replace(new RegExp(Prototype.ScriptFragment, 'img'), '');
+ },
+
+ extractScripts: function() {
+ var matchAll = new RegExp(Prototype.ScriptFragment, 'img');
+ var matchOne = new RegExp(Prototype.ScriptFragment, 'im');
+ return (this.match(matchAll) || []).map(function(scriptTag) {
+ return (scriptTag.match(matchOne) || ['', ''])[1];
+ });
+ },
+
+ evalScripts: function() {
+ return this.extractScripts().map(function(script) { return eval(script) });
+ },
+
+ escapeHTML: function() {
+ var div = document.createElement('div');
+ var text = document.createTextNode(this);
+ div.appendChild(text);
+ return div.innerHTML;
+ },
+
+ unescapeHTML: function() {
+ var div = document.createElement('div');
+ div.innerHTML = this.stripTags();
+ return div.childNodes[0] ? (div.childNodes.length > 1 ?
+ $A(div.childNodes).inject('',function(memo,node){ return memo+node.nodeValue }) :
+ div.childNodes[0].nodeValue) : '';
+ },
+
+ toQueryParams: function(separator) {
+ var match = this.strip().match(/([^?#]*)(#.*)?$/);
+ if (!match) return {};
+
+ return match[1].split(separator || '&').inject({}, function(hash, pair) {
+ if ((pair = pair.split('='))[0]) {
+ var name = decodeURIComponent(pair[0]);
+ var value = pair[1] ? decodeURIComponent(pair[1]) : undefined;
+
+ if (hash[name] !== undefined) {
+ if (hash[name].constructor != Array)
+ hash[name] = [hash[name]];
+ if (value) hash[name].push(value);
+ }
+ else hash[name] = value;
+ }
+ return hash;
+ });
+ },
+
+ toArray: function() {
+ return this.split('');
+ },
+
+ succ: function() {
+ return this.slice(0, this.length - 1) +
+ String.fromCharCode(this.charCodeAt(this.length - 1) + 1);
+ },
+
+ camelize: function() {
+ var parts = this.split('-'), len = parts.length;
+ if (len == 1) return parts[0];
+
+ var camelized = this.charAt(0) == '-'
+ ? parts[0].charAt(0).toUpperCase() + parts[0].substring(1)
+ : parts[0];
+
+ for (var i = 1; i < len; i++)
+ camelized += parts[i].charAt(0).toUpperCase() + parts[i].substring(1);
+
+ return camelized;
+ },
+
+ capitalize: function(){
+ return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
+ },
+
+ underscore: function() {
+ return this.gsub(/::/, '/').gsub(/([A-Z]+)([A-Z][a-z])/,'#{1}_#{2}').gsub(/([a-z\d])([A-Z])/,'#{1}_#{2}').gsub(/-/,'_').toLowerCase();
+ },
+
+ dasherize: function() {
+ return this.gsub(/_/,'-');
+ },
+
+ inspect: function(useDoubleQuotes) {
+ var escapedString = this.replace(/\\/g, '\\\\');
+ if (useDoubleQuotes)
+ return '"' + escapedString.replace(/"/g, '\\"') + '"';
+ else
+ return "'" + escapedString.replace(/'/g, '\\\'') + "'";
+ }
+});
+
+String.prototype.gsub.prepareReplacement = function(replacement) {
+ if (typeof replacement == 'function') return replacement;
+ var template = new Template(replacement);
+ return function(match) { return template.evaluate(match) };
+}
+
+String.prototype.parseQuery = String.prototype.toQueryParams;
+
+var Template = Class.create();
+Template.Pattern = /(^|.|\r|\n)(#\{(.*?)\})/;
+Template.prototype = {
+ initialize: function(template, pattern) {
+ this.template = template.toString();
+ this.pattern = pattern || Template.Pattern;
+ },
+
+ evaluate: function(object) {
+ return this.template.gsub(this.pattern, function(match) {
+ var before = match[1];
+ if (before == '\\') return match[2];
+ return before + String.interpret(object[match[3]]);
+ });
+ }
+}
+
+var $break = new Object();
+var $continue = new Object();
+
+var Enumerable = {
+ each: function(iterator) {
+ var index = 0;
+ try {
+ this._each(function(value) {
+ try {
+ iterator(value, index++);
+ } catch (e) {
+ if (e != $continue) throw e;
+ }
+ });
+ } catch (e) {
+ if (e != $break) throw e;
+ }
+ return this;
+ },
+
+ eachSlice: function(number, iterator) {
+ var index = -number, slices = [], array = this.toArray();
+ while ((index += number) < array.length)
+ slices.push(array.slice(index, index+number));
+ return slices.map(iterator);
+ },
+
+ all: function(iterator) {
+ var result = true;
+ this.each(function(value, index) {
+ result = result && !!(iterator || Prototype.K)(value, index);
+ if (!result) throw $break;
+ });
+ return result;
+ },
+
+ any: function(iterator) {
+ var result = false;
+ this.each(function(value, index) {
+ if (result = !!(iterator || Prototype.K)(value, index))
+ throw $break;
+ });
+ return result;
+ },
+
+ collect: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push((iterator || Prototype.K)(value, index));
+ });
+ return results;
+ },
+
+ detect: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ if (iterator(value, index)) {
+ result = value;
+ throw $break;
+ }
+ });
+ return result;
+ },
+
+ findAll: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ grep: function(pattern, iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ var stringValue = value.toString();
+ if (stringValue.match(pattern))
+ results.push((iterator || Prototype.K)(value, index));
+ })
+ return results;
+ },
+
+ include: function(object) {
+ var found = false;
+ this.each(function(value) {
+ if (value == object) {
+ found = true;
+ throw $break;
+ }
+ });
+ return found;
+ },
+
+ inGroupsOf: function(number, fillWith) {
+ fillWith = fillWith === undefined ? null : fillWith;
+ return this.eachSlice(number, function(slice) {
+ while(slice.length < number) slice.push(fillWith);
+ return slice;
+ });
+ },
+
+ inject: function(memo, iterator) {
+ this.each(function(value, index) {
+ memo = iterator(memo, value, index);
+ });
+ return memo;
+ },
+
+ invoke: function(method) {
+ var args = $A(arguments).slice(1);
+ return this.map(function(value) {
+ return value[method].apply(value, args);
+ });
+ },
+
+ max: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (result == undefined || value >= result)
+ result = value;
+ });
+ return result;
+ },
+
+ min: function(iterator) {
+ var result;
+ this.each(function(value, index) {
+ value = (iterator || Prototype.K)(value, index);
+ if (result == undefined || value < result)
+ result = value;
+ });
+ return result;
+ },
+
+ partition: function(iterator) {
+ var trues = [], falses = [];
+ this.each(function(value, index) {
+ ((iterator || Prototype.K)(value, index) ?
+ trues : falses).push(value);
+ });
+ return [trues, falses];
+ },
+
+ pluck: function(property) {
+ var results = [];
+ this.each(function(value, index) {
+ results.push(value[property]);
+ });
+ return results;
+ },
+
+ reject: function(iterator) {
+ var results = [];
+ this.each(function(value, index) {
+ if (!iterator(value, index))
+ results.push(value);
+ });
+ return results;
+ },
+
+ sortBy: function(iterator) {
+ return this.map(function(value, index) {
+ return {value: value, criteria: iterator(value, index)};
+ }).sort(function(left, right) {
+ var a = left.criteria, b = right.criteria;
+ return a < b ? -1 : a > b ? 1 : 0;
+ }).pluck('value');
+ },
+
+ toArray: function() {
+ return this.map();
+ },
+
+ zip: function() {
+ var iterator = Prototype.K, args = $A(arguments);
+ if (typeof args.last() == 'function')
+ iterator = args.pop();
+
+ var collections = [this].concat(args).map($A);
+ return this.map(function(value, index) {
+ return iterator(collections.pluck(index));
+ });
+ },
+
+ size: function() {
+ return this.toArray().length;
+ },
+
+ inspect: function() {
+ return '#';
+ }
+}
+
+Object.extend(Enumerable, {
+ map: Enumerable.collect,
+ find: Enumerable.detect,
+ select: Enumerable.findAll,
+ member: Enumerable.include,
+ entries: Enumerable.toArray
+});
+var $A = Array.from = function(iterable) {
+ if (!iterable) return [];
+ if (iterable.toArray) {
+ return iterable.toArray();
+ } else {
+ var results = [];
+ for (var i = 0, length = iterable.length; i < length; i++)
+ results.push(iterable[i]);
+ return results;
+ }
+}
+
+Object.extend(Array.prototype, Enumerable);
+
+if (!Array.prototype._reverse)
+ Array.prototype._reverse = Array.prototype.reverse;
+
+Object.extend(Array.prototype, {
+ _each: function(iterator) {
+ for (var i = 0, length = this.length; i < length; i++)
+ iterator(this[i]);
+ },
+
+ clear: function() {
+ this.length = 0;
+ return this;
+ },
+
+ first: function() {
+ return this[0];
+ },
+
+ last: function() {
+ return this[this.length - 1];
+ },
+
+ compact: function() {
+ return this.select(function(value) {
+ return value != null;
+ });
+ },
+
+ flatten: function() {
+ return this.inject([], function(array, value) {
+ return array.concat(value && value.constructor == Array ?
+ value.flatten() : [value]);
+ });
+ },
+
+ without: function() {
+ var values = $A(arguments);
+ return this.select(function(value) {
+ return !values.include(value);
+ });
+ },
+
+ indexOf: function(object) {
+ for (var i = 0, length = this.length; i < length; i++)
+ if (this[i] == object) return i;
+ return -1;
+ },
+
+ reverse: function(inline) {
+ return (inline !== false ? this : this.toArray())._reverse();
+ },
+
+ reduce: function() {
+ return this.length > 1 ? this : this[0];
+ },
+
+ uniq: function() {
+ return this.inject([], function(array, value) {
+ return array.include(value) ? array : array.concat([value]);
+ });
+ },
+
+ clone: function() {
+ return [].concat(this);
+ },
+
+ size: function() {
+ return this.length;
+ },
+
+ inspect: function() {
+ return '[' + this.map(Object.inspect).join(', ') + ']';
+ }
+});
+
+Array.prototype.toArray = Array.prototype.clone;
+
+function $w(string){
+ string = string.strip();
+ return string ? string.split(/\s+/) : [];
+}
+
+if(window.opera){
+ Array.prototype.concat = function(){
+ var array = [];
+ for(var i = 0, length = this.length; i < length; i++) array.push(this[i]);
+ for(var i = 0, length = arguments.length; i < length; i++) {
+ if(arguments[i].constructor == Array) {
+ for(var j = 0, arrayLength = arguments[i].length; j < arrayLength; j++)
+ array.push(arguments[i][j]);
+ } else {
+ array.push(arguments[i]);
+ }
+ }
+ return array;
+ }
+}
+var Hash = function(obj) {
+ Object.extend(this, obj || {});
+};
+
+Object.extend(Hash, {
+ toQueryString: function(obj) {
+ var parts = [];
+
+ this.prototype._each.call(obj, function(pair) {
+ if (!pair.key) return;
+
+ if (pair.value && pair.value.constructor == Array) {
+ var values = pair.value.compact();
+ if (values.length < 2) pair.value = values.reduce();
+ else {
+ key = encodeURIComponent(pair.key);
+ values.each(function(value) {
+ value = value != undefined ? encodeURIComponent(value) : '';
+ parts.push(key + '=' + encodeURIComponent(value));
+ });
+ return;
+ }
+ }
+ if (pair.value == undefined) pair[1] = '';
+ parts.push(pair.map(encodeURIComponent).join('='));
+ });
+
+ return parts.join('&');
+ }
+});
+
+Object.extend(Hash.prototype, Enumerable);
+Object.extend(Hash.prototype, {
+ _each: function(iterator) {
+ for (var key in this) {
+ var value = this[key];
+ if (value && value == Hash.prototype[key]) continue;
+
+ var pair = [key, value];
+ pair.key = key;
+ pair.value = value;
+ iterator(pair);
+ }
+ },
+
+ keys: function() {
+ return this.pluck('key');
+ },
+
+ values: function() {
+ return this.pluck('value');
+ },
+
+ merge: function(hash) {
+ return $H(hash).inject(this, function(mergedHash, pair) {
+ mergedHash[pair.key] = pair.value;
+ return mergedHash;
+ });
+ },
+
+ remove: function() {
+ var result;
+ for(var i = 0, length = arguments.length; i < length; i++) {
+ var value = this[arguments[i]];
+ if (value !== undefined){
+ if (result === undefined) result = value;
+ else {
+ if (result.constructor != Array) result = [result];
+ result.push(value)
+ }
+ }
+ delete this[arguments[i]];
+ }
+ return result;
+ },
+
+ toQueryString: function() {
+ return Hash.toQueryString(this);
+ },
+
+ inspect: function() {
+ return '#';
+ }
+});
+
+function $H(object) {
+ if (object && object.constructor == Hash) return object;
+ return new Hash(object);
+};
+ObjectRange = Class.create();
+Object.extend(ObjectRange.prototype, Enumerable);
+Object.extend(ObjectRange.prototype, {
+ initialize: function(start, end, exclusive) {
+ this.start = start;
+ this.end = end;
+ this.exclusive = exclusive;
+ },
+
+ _each: function(iterator) {
+ var value = this.start;
+ while (this.include(value)) {
+ iterator(value);
+ value = value.succ();
+ }
+ },
+
+ include: function(value) {
+ if (value < this.start)
+ return false;
+ if (this.exclusive)
+ return value < this.end;
+ return value <= this.end;
+ }
+});
+
+var $R = function(start, end, exclusive) {
+ return new ObjectRange(start, end, exclusive);
+}
+
+var Ajax = {
+ getTransport: function() {
+ return Try.these(
+ function() {return new XMLHttpRequest()},
+ function() {return new ActiveXObject('Msxml2.XMLHTTP')},
+ function() {return new ActiveXObject('Microsoft.XMLHTTP')}
+ ) || false;
+ },
+
+ activeRequestCount: 0
+}
+
+Ajax.Responders = {
+ responders: [],
+
+ _each: function(iterator) {
+ this.responders._each(iterator);
+ },
+
+ register: function(responder) {
+ if (!this.include(responder))
+ this.responders.push(responder);
+ },
+
+ unregister: function(responder) {
+ this.responders = this.responders.without(responder);
+ },
+
+ dispatch: function(callback, request, transport, json) {
+ this.each(function(responder) {
+ if (typeof responder[callback] == 'function') {
+ try {
+ responder[callback].apply(responder, [request, transport, json]);
+ } catch (e) {}
+ }
+ });
+ }
+};
+
+Object.extend(Ajax.Responders, Enumerable);
+
+Ajax.Responders.register({
+ onCreate: function() {
+ Ajax.activeRequestCount++;
+ },
+ onComplete: function() {
+ Ajax.activeRequestCount--;
+ }
+});
+
+Ajax.Base = function() {};
+Ajax.Base.prototype = {
+ setOptions: function(options) {
+ this.options = {
+ method: 'post',
+ asynchronous: true,
+ contentType: 'application/x-www-form-urlencoded',
+ encoding: 'UTF-8',
+ parameters: ''
+ }
+ Object.extend(this.options, options || {});
+
+ this.options.method = this.options.method.toLowerCase();
+ if (typeof this.options.parameters == 'string')
+ this.options.parameters = this.options.parameters.toQueryParams();
+ }
+}
+
+Ajax.Request = Class.create();
+Ajax.Request.Events =
+ ['Uninitialized', 'Loading', 'Loaded', 'Interactive', 'Complete'];
+
+Ajax.Request.prototype = Object.extend(new Ajax.Base(), {
+ _complete: false,
+
+ initialize: function(url, options) {
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+ this.request(url);
+ },
+
+ request: function(url) {
+ this.url = url;
+ this.method = this.options.method;
+ var params = this.options.parameters;
+
+ if (!['get', 'post'].include(this.method)) {
+ // simulate other verbs over post
+ params['_method'] = this.method;
+ this.method = 'post';
+ }
+
+ params = Hash.toQueryString(params);
+ if (params && /Konqueror|Safari|KHTML/.test(navigator.userAgent)) params += '&_='
+
+ // when GET, append parameters to URL
+ if (this.method == 'get' && params)
+ this.url += (this.url.indexOf('?') > -1 ? '&' : '?') + params;
+
+ try {
+ Ajax.Responders.dispatch('onCreate', this, this.transport);
+
+ this.transport.open(this.method.toUpperCase(), this.url,
+ this.options.asynchronous);
+
+ if (this.options.asynchronous)
+ setTimeout(function() { this.respondToReadyState(1) }.bind(this), 10);
+
+ this.transport.onreadystatechange = this.onStateChange.bind(this);
+ this.setRequestHeaders();
+
+ var body = this.method == 'post' ? (this.options.postBody || params) : null;
+
+ this.transport.send(body);
+
+ /* Force Firefox to handle ready state 4 for synchronous requests */
+ if (!this.options.asynchronous && this.transport.overrideMimeType)
+ this.onStateChange();
+
+ }
+ catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ onStateChange: function() {
+ var readyState = this.transport.readyState;
+ if (readyState > 1 && !((readyState == 4) && this._complete))
+ this.respondToReadyState(this.transport.readyState);
+ },
+
+ setRequestHeaders: function() {
+ var headers = {
+ 'X-Requested-With': 'XMLHttpRequest',
+ 'X-Prototype-Version': Prototype.Version,
+ 'Accept': 'text/javascript, text/html, application/xml, text/xml, */*'
+ };
+
+ if (this.method == 'post') {
+ headers['Content-type'] = this.options.contentType +
+ (this.options.encoding ? '; charset=' + this.options.encoding : '');
+
+ /* Force "Connection: close" for older Mozilla browsers to work
+ * around a bug where XMLHttpRequest sends an incorrect
+ * Content-length header. See Mozilla Bugzilla #246651.
+ */
+ if (this.transport.overrideMimeType &&
+ (navigator.userAgent.match(/Gecko\/(\d{4})/) || [0,2005])[1] < 2005)
+ headers['Connection'] = 'close';
+ }
+
+ // user-defined headers
+ if (typeof this.options.requestHeaders == 'object') {
+ var extras = this.options.requestHeaders;
+
+ if (typeof extras.push == 'function')
+ for (var i = 0, length = extras.length; i < length; i += 2)
+ headers[extras[i]] = extras[i+1];
+ else
+ $H(extras).each(function(pair) { headers[pair.key] = pair.value });
+ }
+
+ for (var name in headers)
+ this.transport.setRequestHeader(name, headers[name]);
+ },
+
+ success: function() {
+ return !this.transport.status
+ || (this.transport.status >= 200 && this.transport.status < 300);
+ },
+
+ respondToReadyState: function(readyState) {
+ var state = Ajax.Request.Events[readyState];
+ var transport = this.transport, json = this.evalJSON();
+
+ if (state == 'Complete') {
+ try {
+ this._complete = true;
+ (this.options['on' + this.transport.status]
+ || this.options['on' + (this.success() ? 'Success' : 'Failure')]
+ || Prototype.emptyFunction)(transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if ((this.getHeader('Content-type') || 'text/javascript').strip().
+ match(/^(text|application)\/(x-)?(java|ecma)script(;.*)?$/i))
+ this.evalResponse();
+ }
+
+ try {
+ (this.options['on' + state] || Prototype.emptyFunction)(transport, json);
+ Ajax.Responders.dispatch('on' + state, this, transport, json);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+
+ if (state == 'Complete') {
+ // avoid memory leak in MSIE: clean up
+ this.transport.onreadystatechange = Prototype.emptyFunction;
+ }
+ },
+
+ getHeader: function(name) {
+ try {
+ return this.transport.getResponseHeader(name);
+ } catch (e) { return null }
+ },
+
+ evalJSON: function() {
+ try {
+ var json = this.getHeader('X-JSON');
+ return json ? eval('(' + json + ')') : null;
+ } catch (e) { return null }
+ },
+
+ evalResponse: function() {
+ try {
+ return eval(this.transport.responseText);
+ } catch (e) {
+ this.dispatchException(e);
+ }
+ },
+
+ dispatchException: function(exception) {
+ (this.options.onException || Prototype.emptyFunction)(this, exception);
+ Ajax.Responders.dispatch('onException', this, exception);
+ }
+});
+
+Ajax.Updater = Class.create();
+
+Object.extend(Object.extend(Ajax.Updater.prototype, Ajax.Request.prototype), {
+ initialize: function(container, url, options) {
+ this.container = {
+ success: (container.success || container),
+ failure: (container.failure || (container.success ? null : container))
+ }
+
+ this.transport = Ajax.getTransport();
+ this.setOptions(options);
+
+ var onComplete = this.options.onComplete || Prototype.emptyFunction;
+ this.options.onComplete = (function(transport, param) {
+ this.updateContent();
+ onComplete(transport, param);
+ }).bind(this);
+
+ this.request(url);
+ },
+
+ updateContent: function() {
+ var receiver = this.container[this.success() ? 'success' : 'failure'];
+ var response = this.transport.responseText;
+
+ if (!this.options.evalScripts) response = response.stripScripts();
+
+ if (receiver = $(receiver)) {
+ if (this.options.insertion)
+ new this.options.insertion(receiver, response);
+ else
+ receiver.update(response);
+ }
+
+ if (this.success()) {
+ if (this.onComplete)
+ setTimeout(this.onComplete.bind(this), 10);
+ }
+ }
+});
+
+Ajax.PeriodicalUpdater = Class.create();
+Ajax.PeriodicalUpdater.prototype = Object.extend(new Ajax.Base(), {
+ initialize: function(container, url, options) {
+ this.setOptions(options);
+ this.onComplete = this.options.onComplete;
+
+ this.frequency = (this.options.frequency || 2);
+ this.decay = (this.options.decay || 1);
+
+ this.updater = {};
+ this.container = container;
+ this.url = url;
+
+ this.start();
+ },
+
+ start: function() {
+ this.options.onComplete = this.updateComplete.bind(this);
+ this.onTimerEvent();
+ },
+
+ stop: function() {
+ this.updater.options.onComplete = undefined;
+ clearTimeout(this.timer);
+ (this.onComplete || Prototype.emptyFunction).apply(this, arguments);
+ },
+
+ updateComplete: function(request) {
+ if (this.options.decay) {
+ this.decay = (request.responseText == this.lastText ?
+ this.decay * this.options.decay : 1);
+
+ this.lastText = request.responseText;
+ }
+ this.timer = setTimeout(this.onTimerEvent.bind(this),
+ this.decay * this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ this.updater = new Ajax.Updater(this.container, this.url, this.options);
+ }
+});
+function $(element) {
+ if (arguments.length > 1) {
+ for (var i = 0, elements = [], length = arguments.length; i < length; i++)
+ elements.push($(arguments[i]));
+ return elements;
+ }
+ if (typeof element == 'string')
+ element = document.getElementById(element);
+ return Element.extend(element);
+}
+
+if (Prototype.BrowserFeatures.XPath) {
+ document._getElementsByXPath = function(expression, parentElement) {
+ var results = [];
+ var query = document.evaluate(expression, $(parentElement) || document,
+ null, XPathResult.ORDERED_NODE_SNAPSHOT_TYPE, null);
+ for (var i = 0, length = query.snapshotLength; i < length; i++)
+ results.push(query.snapshotItem(i));
+ return results;
+ };
+}
+
+document.getElementsByClassName = function(className, parentElement) {
+ if (Prototype.BrowserFeatures.XPath) {
+ var q = ".//*[contains(concat(' ', @class, ' '), ' " + className + " ')]";
+ return document._getElementsByXPath(q, parentElement);
+ } else {
+ var children = ($(parentElement) || document.body).getElementsByTagName('*');
+ var elements = [], child;
+ for (var i = 0, length = children.length; i < length; i++) {
+ child = children[i];
+ if (Element.hasClassName(child, className))
+ elements.push(Element.extend(child));
+ }
+ return elements;
+ }
+};
+
+/*--------------------------------------------------------------------------*/
+
+if (!window.Element)
+ var Element = new Object();
+
+Element.extend = function(element) {
+ if (!element || _nativeExtensions || element.nodeType == 3) return element;
+
+ if (!element._extended && element.tagName && element != window) {
+ var methods = Object.clone(Element.Methods), cache = Element.extend.cache;
+
+ if (element.tagName == 'FORM')
+ Object.extend(methods, Form.Methods);
+ if (['INPUT', 'TEXTAREA', 'SELECT'].include(element.tagName))
+ Object.extend(methods, Form.Element.Methods);
+
+ Object.extend(methods, Element.Methods.Simulated);
+
+ for (var property in methods) {
+ var value = methods[property];
+ if (typeof value == 'function' && !(property in element))
+ element[property] = cache.findOrStore(value);
+ }
+ }
+
+ element._extended = true;
+ return element;
+};
+
+Element.extend.cache = {
+ findOrStore: function(value) {
+ return this[value] = this[value] || function() {
+ return value.apply(null, [this].concat($A(arguments)));
+ }
+ }
+};
+
+Element.Methods = {
+ visible: function(element) {
+ return $(element).style.display != 'none';
+ },
+
+ toggle: function(element) {
+ element = $(element);
+ Element[Element.visible(element) ? 'hide' : 'show'](element);
+ return element;
+ },
+
+ hide: function(element) {
+ $(element).style.display = 'none';
+ return element;
+ },
+
+ show: function(element) {
+ $(element).style.display = '';
+ return element;
+ },
+
+ remove: function(element) {
+ element = $(element);
+ element.parentNode.removeChild(element);
+ return element;
+ },
+
+ update: function(element, html) {
+ html = typeof html == 'undefined' ? '' : html.toString();
+ $(element).innerHTML = html.stripScripts();
+ setTimeout(function() {html.evalScripts()}, 10);
+ return element;
+ },
+
+ replace: function(element, html) {
+ element = $(element);
+ html = typeof html == 'undefined' ? '' : html.toString();
+ if (element.outerHTML) {
+ element.outerHTML = html.stripScripts();
+ } else {
+ var range = element.ownerDocument.createRange();
+ range.selectNodeContents(element);
+ element.parentNode.replaceChild(
+ range.createContextualFragment(html.stripScripts()), element);
+ }
+ setTimeout(function() {html.evalScripts()}, 10);
+ return element;
+ },
+
+ inspect: function(element) {
+ element = $(element);
+ var result = '<' + element.tagName.toLowerCase();
+ $H({'id': 'id', 'className': 'class'}).each(function(pair) {
+ var property = pair.first(), attribute = pair.last();
+ var value = (element[property] || '').toString();
+ if (value) result += ' ' + attribute + '=' + value.inspect(true);
+ });
+ return result + '>';
+ },
+
+ recursivelyCollect: function(element, property) {
+ element = $(element);
+ var elements = [];
+ while (element = element[property])
+ if (element.nodeType == 1)
+ elements.push(Element.extend(element));
+ return elements;
+ },
+
+ ancestors: function(element) {
+ return $(element).recursivelyCollect('parentNode');
+ },
+
+ descendants: function(element) {
+ return $A($(element).getElementsByTagName('*'));
+ },
+
+ immediateDescendants: function(element) {
+ if (!(element = $(element).firstChild)) return [];
+ while (element && element.nodeType != 1) element = element.nextSibling;
+ if (element) return [element].concat($(element).nextSiblings());
+ return [];
+ },
+
+ previousSiblings: function(element) {
+ return $(element).recursivelyCollect('previousSibling');
+ },
+
+ nextSiblings: function(element) {
+ return $(element).recursivelyCollect('nextSibling');
+ },
+
+ siblings: function(element) {
+ element = $(element);
+ return element.previousSiblings().reverse().concat(element.nextSiblings());
+ },
+
+ match: function(element, selector) {
+ if (typeof selector == 'string')
+ selector = new Selector(selector);
+ return selector.match($(element));
+ },
+
+ up: function(element, expression, index) {
+ return Selector.findElement($(element).ancestors(), expression, index);
+ },
+
+ down: function(element, expression, index) {
+ return Selector.findElement($(element).descendants(), expression, index);
+ },
+
+ previous: function(element, expression, index) {
+ return Selector.findElement($(element).previousSiblings(), expression, index);
+ },
+
+ next: function(element, expression, index) {
+ return Selector.findElement($(element).nextSiblings(), expression, index);
+ },
+
+ getElementsBySelector: function() {
+ var args = $A(arguments), element = $(args.shift());
+ return Selector.findChildElements(element, args);
+ },
+
+ getElementsByClassName: function(element, className) {
+ return document.getElementsByClassName(className, element);
+ },
+
+ readAttribute: function(element, name) {
+ element = $(element);
+ if (document.all && !window.opera) {
+ var t = Element._attributeTranslations;
+ if (t.values[name]) return t.values[name](element, name);
+ if (t.names[name]) name = t.names[name];
+ var attribute = element.attributes[name];
+ if(attribute) return attribute.nodeValue;
+ }
+ return element.getAttribute(name);
+ },
+
+ getHeight: function(element) {
+ return $(element).getDimensions().height;
+ },
+
+ getWidth: function(element) {
+ return $(element).getDimensions().width;
+ },
+
+ classNames: function(element) {
+ return new Element.ClassNames(element);
+ },
+
+ hasClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ var elementClassName = element.className;
+ if (elementClassName.length == 0) return false;
+ if (elementClassName == className ||
+ elementClassName.match(new RegExp("(^|\\s)" + className + "(\\s|$)")))
+ return true;
+ return false;
+ },
+
+ addClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ Element.classNames(element).add(className);
+ return element;
+ },
+
+ removeClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ Element.classNames(element).remove(className);
+ return element;
+ },
+
+ toggleClassName: function(element, className) {
+ if (!(element = $(element))) return;
+ Element.classNames(element)[element.hasClassName(className) ? 'remove' : 'add'](className);
+ return element;
+ },
+
+ observe: function() {
+ Event.observe.apply(Event, arguments);
+ return $A(arguments).first();
+ },
+
+ stopObserving: function() {
+ Event.stopObserving.apply(Event, arguments);
+ return $A(arguments).first();
+ },
+
+ // removes whitespace-only text node children
+ cleanWhitespace: function(element) {
+ element = $(element);
+ var node = element.firstChild;
+ while (node) {
+ var nextNode = node.nextSibling;
+ if (node.nodeType == 3 && !/\S/.test(node.nodeValue))
+ element.removeChild(node);
+ node = nextNode;
+ }
+ return element;
+ },
+
+ empty: function(element) {
+ return $(element).innerHTML.match(/^\s*$/);
+ },
+
+ descendantOf: function(element, ancestor) {
+ element = $(element), ancestor = $(ancestor);
+ while (element = element.parentNode)
+ if (element == ancestor) return true;
+ return false;
+ },
+
+ scrollTo: function(element) {
+ element = $(element);
+ var pos = Position.cumulativeOffset(element);
+ window.scrollTo(pos[0], pos[1]);
+ return element;
+ },
+
+ getStyle: function(element, style) {
+ element = $(element);
+ if (['float','cssFloat'].include(style))
+ style = (typeof element.style.styleFloat != 'undefined' ? 'styleFloat' : 'cssFloat');
+ style = style.camelize();
+ var value = element.style[style];
+ if (!value) {
+ if (document.defaultView && document.defaultView.getComputedStyle) {
+ var css = document.defaultView.getComputedStyle(element, null);
+ value = css ? css[style] : null;
+ } else if (element.currentStyle) {
+ value = element.currentStyle[style];
+ }
+ }
+
+ if((value == 'auto') && ['width','height'].include(style) && (element.getStyle('display') != 'none'))
+ value = element['offset'+style.capitalize()] + 'px';
+
+ if (window.opera && ['left', 'top', 'right', 'bottom'].include(style))
+ if (Element.getStyle(element, 'position') == 'static') value = 'auto';
+ if(style == 'opacity') {
+ if(value) return parseFloat(value);
+ if(value = (element.getStyle('filter') || '').match(/alpha\(opacity=(.*)\)/))
+ if(value[1]) return parseFloat(value[1]) / 100;
+ return 1.0;
+ }
+ return value == 'auto' ? null : value;
+ },
+
+ setStyle: function(element, style) {
+ element = $(element);
+ for (var name in style) {
+ var value = style[name];
+ if(name == 'opacity') {
+ if (value == 1) {
+ value = (/Gecko/.test(navigator.userAgent) &&
+ !/Konqueror|Safari|KHTML/.test(navigator.userAgent)) ? 0.999999 : 1.0;
+ if(/MSIE/.test(navigator.userAgent) && !window.opera)
+ element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
+ } else if(value == '') {
+ if(/MSIE/.test(navigator.userAgent) && !window.opera)
+ element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'');
+ } else {
+ if(value < 0.00001) value = 0;
+ if(/MSIE/.test(navigator.userAgent) && !window.opera)
+ element.style.filter = element.getStyle('filter').replace(/alpha\([^\)]*\)/gi,'') +
+ 'alpha(opacity='+value*100+')';
+ }
+ } else if(['float','cssFloat'].include(name)) name = (typeof element.style.styleFloat != 'undefined') ? 'styleFloat' : 'cssFloat';
+ element.style[name.camelize()] = value;
+ }
+ return element;
+ },
+
+ getDimensions: function(element) {
+ element = $(element);
+ var display = $(element).getStyle('display');
+ if (display != 'none' && display != null) // Safari bug
+ return {width: element.offsetWidth, height: element.offsetHeight};
+
+ // All *Width and *Height properties give 0 on elements with display none,
+ // so enable the element temporarily
+ var els = element.style;
+ var originalVisibility = els.visibility;
+ var originalPosition = els.position;
+ var originalDisplay = els.display;
+ els.visibility = 'hidden';
+ els.position = 'absolute';
+ els.display = 'block';
+ var originalWidth = element.clientWidth;
+ var originalHeight = element.clientHeight;
+ els.display = originalDisplay;
+ els.position = originalPosition;
+ els.visibility = originalVisibility;
+ return {width: originalWidth, height: originalHeight};
+ },
+
+ makePositioned: function(element) {
+ element = $(element);
+ var pos = Element.getStyle(element, 'position');
+ if (pos == 'static' || !pos) {
+ element._madePositioned = true;
+ element.style.position = 'relative';
+ // Opera returns the offset relative to the positioning context, when an
+ // element is position relative but top and left have not been defined
+ if (window.opera) {
+ element.style.top = 0;
+ element.style.left = 0;
+ }
+ }
+ return element;
+ },
+
+ undoPositioned: function(element) {
+ element = $(element);
+ if (element._madePositioned) {
+ element._madePositioned = undefined;
+ element.style.position =
+ element.style.top =
+ element.style.left =
+ element.style.bottom =
+ element.style.right = '';
+ }
+ return element;
+ },
+
+ makeClipping: function(element) {
+ element = $(element);
+ if (element._overflow) return element;
+ element._overflow = element.style.overflow || 'auto';
+ if ((Element.getStyle(element, 'overflow') || 'visible') != 'hidden')
+ element.style.overflow = 'hidden';
+ return element;
+ },
+
+ undoClipping: function(element) {
+ element = $(element);
+ if (!element._overflow) return element;
+ element.style.overflow = element._overflow == 'auto' ? '' : element._overflow;
+ element._overflow = null;
+ return element;
+ }
+};
+
+Object.extend(Element.Methods, {childOf: Element.Methods.descendantOf});
+
+Element._attributeTranslations = {};
+
+Element._attributeTranslations.names = {
+ colspan: "colSpan",
+ rowspan: "rowSpan",
+ valign: "vAlign",
+ datetime: "dateTime",
+ accesskey: "accessKey",
+ tabindex: "tabIndex",
+ enctype: "encType",
+ maxlength: "maxLength",
+ readonly: "readOnly",
+ longdesc: "longDesc"
+};
+
+Element._attributeTranslations.values = {
+ _getAttr: function(element, attribute) {
+ return element.getAttribute(attribute, 2);
+ },
+
+ _flag: function(element, attribute) {
+ return $(element).hasAttribute(attribute) ? attribute : null;
+ },
+
+ style: function(element) {
+ return element.style.cssText.toLowerCase();
+ },
+
+ title: function(element) {
+ var node = element.getAttributeNode('title');
+ return node.specified ? node.nodeValue : null;
+ }
+};
+
+Object.extend(Element._attributeTranslations.values, {
+ href: Element._attributeTranslations.values._getAttr,
+ src: Element._attributeTranslations.values._getAttr,
+ disabled: Element._attributeTranslations.values._flag,
+ checked: Element._attributeTranslations.values._flag,
+ readonly: Element._attributeTranslations.values._flag,
+ multiple: Element._attributeTranslations.values._flag
+});
+
+Element.Methods.Simulated = {
+ hasAttribute: function(element, attribute) {
+ var t = Element._attributeTranslations;
+ attribute = t.names[attribute] || attribute;
+ return $(element).getAttributeNode(attribute).specified;
+ }
+};
+
+// IE is missing .innerHTML support for TABLE-related elements
+if (document.all && !window.opera){
+ Element.Methods.update = function(element, html) {
+ element = $(element);
+ html = typeof html == 'undefined' ? '' : html.toString();
+ var tagName = element.tagName.toUpperCase();
+ if (['THEAD','TBODY','TR','TD'].include(tagName)) {
+ var div = document.createElement('div');
+ switch (tagName) {
+ case 'THEAD':
+ case 'TBODY':
+ div.innerHTML = '' + html.stripScripts() + '
';
+ depth = 2;
+ break;
+ case 'TR':
+ div.innerHTML = '' + html.stripScripts() + '
';
+ depth = 3;
+ break;
+ case 'TD':
+ div.innerHTML = '' + html.stripScripts() + '
';
+ depth = 4;
+ }
+ $A(element.childNodes).each(function(node){
+ element.removeChild(node)
+ });
+ depth.times(function(){ div = div.firstChild });
+
+ $A(div.childNodes).each(
+ function(node){ element.appendChild(node) });
+ } else {
+ element.innerHTML = html.stripScripts();
+ }
+ setTimeout(function() {html.evalScripts()}, 10);
+ return element;
+ }
+};
+
+Object.extend(Element, Element.Methods);
+
+var _nativeExtensions = false;
+
+if(/Konqueror|Safari|KHTML/.test(navigator.userAgent))
+ ['', 'Form', 'Input', 'TextArea', 'Select'].each(function(tag) {
+ var className = 'HTML' + tag + 'Element';
+ if(window[className]) return;
+ var klass = window[className] = {};
+ klass.prototype = document.createElement(tag ? tag.toLowerCase() : 'div').__proto__;
+ });
+
+Element.addMethods = function(methods) {
+ Object.extend(Element.Methods, methods || {});
+
+ function copy(methods, destination, onlyIfAbsent) {
+ onlyIfAbsent = onlyIfAbsent || false;
+ var cache = Element.extend.cache;
+ for (var property in methods) {
+ var value = methods[property];
+ if (!onlyIfAbsent || !(property in destination))
+ destination[property] = cache.findOrStore(value);
+ }
+ }
+
+ if (typeof HTMLElement != 'undefined') {
+ copy(Element.Methods, HTMLElement.prototype);
+ copy(Element.Methods.Simulated, HTMLElement.prototype, true);
+ copy(Form.Methods, HTMLFormElement.prototype);
+ [HTMLInputElement, HTMLTextAreaElement, HTMLSelectElement].each(function(klass) {
+ copy(Form.Element.Methods, klass.prototype);
+ });
+ _nativeExtensions = true;
+ }
+}
+
+var Toggle = new Object();
+Toggle.display = Element.toggle;
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.Insertion = function(adjacency) {
+ this.adjacency = adjacency;
+}
+
+Abstract.Insertion.prototype = {
+ initialize: function(element, content) {
+ this.element = $(element);
+ this.content = content.stripScripts();
+
+ if (this.adjacency && this.element.insertAdjacentHTML) {
+ try {
+ this.element.insertAdjacentHTML(this.adjacency, this.content);
+ } catch (e) {
+ var tagName = this.element.tagName.toUpperCase();
+ if (['TBODY', 'TR'].include(tagName)) {
+ this.insertContent(this.contentFromAnonymousTable());
+ } else {
+ throw e;
+ }
+ }
+ } else {
+ this.range = this.element.ownerDocument.createRange();
+ if (this.initializeRange) this.initializeRange();
+ this.insertContent([this.range.createContextualFragment(this.content)]);
+ }
+
+ setTimeout(function() {content.evalScripts()}, 10);
+ },
+
+ contentFromAnonymousTable: function() {
+ var div = document.createElement('div');
+ div.innerHTML = '';
+ return $A(div.childNodes[0].childNodes[0].childNodes);
+ }
+}
+
+var Insertion = new Object();
+
+Insertion.Before = Class.create();
+Insertion.Before.prototype = Object.extend(new Abstract.Insertion('beforeBegin'), {
+ initializeRange: function() {
+ this.range.setStartBefore(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment, this.element);
+ }).bind(this));
+ }
+});
+
+Insertion.Top = Class.create();
+Insertion.Top.prototype = Object.extend(new Abstract.Insertion('afterBegin'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(true);
+ },
+
+ insertContent: function(fragments) {
+ fragments.reverse(false).each((function(fragment) {
+ this.element.insertBefore(fragment, this.element.firstChild);
+ }).bind(this));
+ }
+});
+
+Insertion.Bottom = Class.create();
+Insertion.Bottom.prototype = Object.extend(new Abstract.Insertion('beforeEnd'), {
+ initializeRange: function() {
+ this.range.selectNodeContents(this.element);
+ this.range.collapse(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.appendChild(fragment);
+ }).bind(this));
+ }
+});
+
+Insertion.After = Class.create();
+Insertion.After.prototype = Object.extend(new Abstract.Insertion('afterEnd'), {
+ initializeRange: function() {
+ this.range.setStartAfter(this.element);
+ },
+
+ insertContent: function(fragments) {
+ fragments.each((function(fragment) {
+ this.element.parentNode.insertBefore(fragment,
+ this.element.nextSibling);
+ }).bind(this));
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Element.ClassNames = Class.create();
+Element.ClassNames.prototype = {
+ initialize: function(element) {
+ this.element = $(element);
+ },
+
+ _each: function(iterator) {
+ this.element.className.split(/\s+/).select(function(name) {
+ return name.length > 0;
+ })._each(iterator);
+ },
+
+ set: function(className) {
+ this.element.className = className;
+ },
+
+ add: function(classNameToAdd) {
+ if (this.include(classNameToAdd)) return;
+ this.set($A(this).concat(classNameToAdd).join(' '));
+ },
+
+ remove: function(classNameToRemove) {
+ if (!this.include(classNameToRemove)) return;
+ this.set($A(this).without(classNameToRemove).join(' '));
+ },
+
+ toString: function() {
+ return $A(this).join(' ');
+ }
+};
+
+Object.extend(Element.ClassNames.prototype, Enumerable);
+var Selector = Class.create();
+Selector.prototype = {
+ initialize: function(expression) {
+ this.params = {classNames: []};
+ this.expression = expression.toString().strip();
+ this.parseExpression();
+ this.compileMatcher();
+ },
+
+ parseExpression: function() {
+ function abort(message) { throw 'Parse error in selector: ' + message; }
+
+ if (this.expression == '') abort('empty expression');
+
+ var params = this.params, expr = this.expression, match, modifier, clause, rest;
+ while (match = expr.match(/^(.*)\[([a-z0-9_:-]+?)(?:([~\|!]?=)(?:"([^"]*)"|([^\]\s]*)))?\]$/i)) {
+ params.attributes = params.attributes || [];
+ params.attributes.push({name: match[2], operator: match[3], value: match[4] || match[5] || ''});
+ expr = match[1];
+ }
+
+ if (expr == '*') return this.params.wildcard = true;
+
+ while (match = expr.match(/^([^a-z0-9_-])?([a-z0-9_-]+)(.*)/i)) {
+ modifier = match[1], clause = match[2], rest = match[3];
+ switch (modifier) {
+ case '#': params.id = clause; break;
+ case '.': params.classNames.push(clause); break;
+ case '':
+ case undefined: params.tagName = clause.toUpperCase(); break;
+ default: abort(expr.inspect());
+ }
+ expr = rest;
+ }
+
+ if (expr.length > 0) abort(expr.inspect());
+ },
+
+ buildMatchExpression: function() {
+ var params = this.params, conditions = [], clause;
+
+ if (params.wildcard)
+ conditions.push('true');
+ if (clause = params.id)
+ conditions.push('element.readAttribute("id") == ' + clause.inspect());
+ if (clause = params.tagName)
+ conditions.push('element.tagName.toUpperCase() == ' + clause.inspect());
+ if ((clause = params.classNames).length > 0)
+ for (var i = 0, length = clause.length; i < length; i++)
+ conditions.push('element.hasClassName(' + clause[i].inspect() + ')');
+ if (clause = params.attributes) {
+ clause.each(function(attribute) {
+ var value = 'element.readAttribute(' + attribute.name.inspect() + ')';
+ var splitValueBy = function(delimiter) {
+ return value + ' && ' + value + '.split(' + delimiter.inspect() + ')';
+ }
+
+ switch (attribute.operator) {
+ case '=': conditions.push(value + ' == ' + attribute.value.inspect()); break;
+ case '~=': conditions.push(splitValueBy(' ') + '.include(' + attribute.value.inspect() + ')'); break;
+ case '|=': conditions.push(
+ splitValueBy('-') + '.first().toUpperCase() == ' + attribute.value.toUpperCase().inspect()
+ ); break;
+ case '!=': conditions.push(value + ' != ' + attribute.value.inspect()); break;
+ case '':
+ case undefined: conditions.push('element.hasAttribute(' + attribute.name.inspect() + ')'); break;
+ default: throw 'Unknown operator ' + attribute.operator + ' in selector';
+ }
+ });
+ }
+
+ return conditions.join(' && ');
+ },
+
+ compileMatcher: function() {
+ this.match = new Function('element', 'if (!element.tagName) return false; \
+ element = $(element); \
+ return ' + this.buildMatchExpression());
+ },
+
+ findElements: function(scope) {
+ var element;
+
+ if (element = $(this.params.id))
+ if (this.match(element))
+ if (!scope || Element.childOf(element, scope))
+ return [element];
+
+ scope = (scope || document).getElementsByTagName(this.params.tagName || '*');
+
+ var results = [];
+ for (var i = 0, length = scope.length; i < length; i++)
+ if (this.match(element = scope[i]))
+ results.push(Element.extend(element));
+
+ return results;
+ },
+
+ toString: function() {
+ return this.expression;
+ }
+}
+
+Object.extend(Selector, {
+ matchElements: function(elements, expression) {
+ var selector = new Selector(expression);
+ return elements.select(selector.match.bind(selector)).map(Element.extend);
+ },
+
+ findElement: function(elements, expression, index) {
+ if (typeof expression == 'number') index = expression, expression = false;
+ return Selector.matchElements(elements, expression || '*')[index || 0];
+ },
+
+ findChildElements: function(element, expressions) {
+ return expressions.map(function(expression) {
+ return expression.match(/[^\s"]+(?:"[^"]*"[^\s"]+)*/g).inject([null], function(results, expr) {
+ var selector = new Selector(expr);
+ return results.inject([], function(elements, result) {
+ return elements.concat(selector.findElements(result || element));
+ });
+ });
+ }).flatten();
+ }
+});
+
+function $$() {
+ return Selector.findChildElements(document, $A(arguments));
+}
+var Form = {
+ reset: function(form) {
+ $(form).reset();
+ return form;
+ },
+
+ serializeElements: function(elements, getHash) {
+ var data = elements.inject({}, function(result, element) {
+ if (!element.disabled && element.name) {
+ var key = element.name, value = $(element).getValue();
+ if (value != undefined) {
+ if (result[key]) {
+ if (result[key].constructor != Array) result[key] = [result[key]];
+ result[key].push(value);
+ }
+ else result[key] = value;
+ }
+ }
+ return result;
+ });
+
+ return getHash ? data : Hash.toQueryString(data);
+ }
+};
+
+Form.Methods = {
+ serialize: function(form, getHash) {
+ return Form.serializeElements(Form.getElements(form), getHash);
+ },
+
+ getElements: function(form) {
+ return $A($(form).getElementsByTagName('*')).inject([],
+ function(elements, child) {
+ if (Form.Element.Serializers[child.tagName.toLowerCase()])
+ elements.push(Element.extend(child));
+ return elements;
+ }
+ );
+ },
+
+ getInputs: function(form, typeName, name) {
+ form = $(form);
+ var inputs = form.getElementsByTagName('input');
+
+ if (!typeName && !name) return $A(inputs).map(Element.extend);
+
+ for (var i = 0, matchingInputs = [], length = inputs.length; i < length; i++) {
+ var input = inputs[i];
+ if ((typeName && input.type != typeName) || (name && input.name != name))
+ continue;
+ matchingInputs.push(Element.extend(input));
+ }
+
+ return matchingInputs;
+ },
+
+ disable: function(form) {
+ form = $(form);
+ form.getElements().each(function(element) {
+ element.blur();
+ element.disabled = 'true';
+ });
+ return form;
+ },
+
+ enable: function(form) {
+ form = $(form);
+ form.getElements().each(function(element) {
+ element.disabled = '';
+ });
+ return form;
+ },
+
+ findFirstElement: function(form) {
+ return $(form).getElements().find(function(element) {
+ return element.type != 'hidden' && !element.disabled &&
+ ['input', 'select', 'textarea'].include(element.tagName.toLowerCase());
+ });
+ },
+
+ focusFirstElement: function(form) {
+ form = $(form);
+ form.findFirstElement().activate();
+ return form;
+ }
+}
+
+Object.extend(Form, Form.Methods);
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element = {
+ focus: function(element) {
+ $(element).focus();
+ return element;
+ },
+
+ select: function(element) {
+ $(element).select();
+ return element;
+ }
+}
+
+Form.Element.Methods = {
+ serialize: function(element) {
+ element = $(element);
+ if (!element.disabled && element.name) {
+ var value = element.getValue();
+ if (value != undefined) {
+ var pair = {};
+ pair[element.name] = value;
+ return Hash.toQueryString(pair);
+ }
+ }
+ return '';
+ },
+
+ getValue: function(element) {
+ element = $(element);
+ var method = element.tagName.toLowerCase();
+ return Form.Element.Serializers[method](element);
+ },
+
+ clear: function(element) {
+ $(element).value = '';
+ return element;
+ },
+
+ present: function(element) {
+ return $(element).value != '';
+ },
+
+ activate: function(element) {
+ element = $(element);
+ element.focus();
+ if (element.select && ( element.tagName.toLowerCase() != 'input' ||
+ !['button', 'reset', 'submit'].include(element.type) ) )
+ element.select();
+ return element;
+ },
+
+ disable: function(element) {
+ element = $(element);
+ element.disabled = true;
+ return element;
+ },
+
+ enable: function(element) {
+ element = $(element);
+ element.blur();
+ element.disabled = false;
+ return element;
+ }
+}
+
+Object.extend(Form.Element, Form.Element.Methods);
+var Field = Form.Element;
+var $F = Form.Element.getValue;
+
+/*--------------------------------------------------------------------------*/
+
+Form.Element.Serializers = {
+ input: function(element) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ return Form.Element.Serializers.inputSelector(element);
+ default:
+ return Form.Element.Serializers.textarea(element);
+ }
+ },
+
+ inputSelector: function(element) {
+ return element.checked ? element.value : null;
+ },
+
+ textarea: function(element) {
+ return element.value;
+ },
+
+ select: function(element) {
+ return this[element.type == 'select-one' ?
+ 'selectOne' : 'selectMany'](element);
+ },
+
+ selectOne: function(element) {
+ var index = element.selectedIndex;
+ return index >= 0 ? this.optionValue(element.options[index]) : null;
+ },
+
+ selectMany: function(element) {
+ var values, length = element.length;
+ if (!length) return null;
+
+ for (var i = 0, values = []; i < length; i++) {
+ var opt = element.options[i];
+ if (opt.selected) values.push(this.optionValue(opt));
+ }
+ return values;
+ },
+
+ optionValue: function(opt) {
+ // extend element because hasAttribute may not be native
+ return Element.extend(opt).hasAttribute('value') ? opt.value : opt.text;
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.TimedObserver = function() {}
+Abstract.TimedObserver.prototype = {
+ initialize: function(element, frequency, callback) {
+ this.frequency = frequency;
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ this.registerCallback();
+ },
+
+ registerCallback: function() {
+ setInterval(this.onTimerEvent.bind(this), this.frequency * 1000);
+ },
+
+ onTimerEvent: function() {
+ var value = this.getValue();
+ var changed = ('string' == typeof this.lastValue && 'string' == typeof value
+ ? this.lastValue != value : String(this.lastValue) != String(value));
+ if (changed) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ }
+}
+
+Form.Element.Observer = Class.create();
+Form.Element.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.Observer = Class.create();
+Form.Observer.prototype = Object.extend(new Abstract.TimedObserver(), {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+
+/*--------------------------------------------------------------------------*/
+
+Abstract.EventObserver = function() {}
+Abstract.EventObserver.prototype = {
+ initialize: function(element, callback) {
+ this.element = $(element);
+ this.callback = callback;
+
+ this.lastValue = this.getValue();
+ if (this.element.tagName.toLowerCase() == 'form')
+ this.registerFormCallbacks();
+ else
+ this.registerCallback(this.element);
+ },
+
+ onElementEvent: function() {
+ var value = this.getValue();
+ if (this.lastValue != value) {
+ this.callback(this.element, value);
+ this.lastValue = value;
+ }
+ },
+
+ registerFormCallbacks: function() {
+ Form.getElements(this.element).each(this.registerCallback.bind(this));
+ },
+
+ registerCallback: function(element) {
+ if (element.type) {
+ switch (element.type.toLowerCase()) {
+ case 'checkbox':
+ case 'radio':
+ Event.observe(element, 'click', this.onElementEvent.bind(this));
+ break;
+ default:
+ Event.observe(element, 'change', this.onElementEvent.bind(this));
+ break;
+ }
+ }
+ }
+}
+
+Form.Element.EventObserver = Class.create();
+Form.Element.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function() {
+ return Form.Element.getValue(this.element);
+ }
+});
+
+Form.EventObserver = Class.create();
+Form.EventObserver.prototype = Object.extend(new Abstract.EventObserver(), {
+ getValue: function() {
+ return Form.serialize(this.element);
+ }
+});
+if (!window.Event) {
+ var Event = new Object();
+}
+
+Object.extend(Event, {
+ KEY_BACKSPACE: 8,
+ KEY_TAB: 9,
+ KEY_RETURN: 13,
+ KEY_ESC: 27,
+ KEY_LEFT: 37,
+ KEY_UP: 38,
+ KEY_RIGHT: 39,
+ KEY_DOWN: 40,
+ KEY_DELETE: 46,
+ KEY_HOME: 36,
+ KEY_END: 35,
+ KEY_PAGEUP: 33,
+ KEY_PAGEDOWN: 34,
+
+ element: function(event) {
+ return event.target || event.srcElement;
+ },
+
+ isLeftClick: function(event) {
+ return (((event.which) && (event.which == 1)) ||
+ ((event.button) && (event.button == 1)));
+ },
+
+ pointerX: function(event) {
+ return event.pageX || (event.clientX +
+ (document.documentElement.scrollLeft || document.body.scrollLeft));
+ },
+
+ pointerY: function(event) {
+ return event.pageY || (event.clientY +
+ (document.documentElement.scrollTop || document.body.scrollTop));
+ },
+
+ stop: function(event) {
+ if (event.preventDefault) {
+ event.preventDefault();
+ event.stopPropagation();
+ } else {
+ event.returnValue = false;
+ event.cancelBubble = true;
+ }
+ },
+
+ // find the first node with the given tagName, starting from the
+ // node the event was triggered on; traverses the DOM upwards
+ findElement: function(event, tagName) {
+ var element = Event.element(event);
+ while (element.parentNode && (!element.tagName ||
+ (element.tagName.toUpperCase() != tagName.toUpperCase())))
+ element = element.parentNode;
+ return element;
+ },
+
+ observers: false,
+
+ _observeAndCache: function(element, name, observer, useCapture) {
+ if (!this.observers) this.observers = [];
+ if (element.addEventListener) {
+ this.observers.push([element, name, observer, useCapture]);
+ element.addEventListener(name, observer, useCapture);
+ } else if (element.attachEvent) {
+ this.observers.push([element, name, observer, useCapture]);
+ element.attachEvent('on' + name, observer);
+ }
+ },
+
+ unloadCache: function() {
+ if (!Event.observers) return;
+ for (var i = 0, length = Event.observers.length; i < length; i++) {
+ Event.stopObserving.apply(this, Event.observers[i]);
+ Event.observers[i][0] = null;
+ }
+ Event.observers = false;
+ },
+
+ observe: function(element, name, observer, useCapture) {
+ element = $(element);
+ useCapture = useCapture || false;
+
+ if (name == 'keypress' &&
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+ || element.attachEvent))
+ name = 'keydown';
+
+ Event._observeAndCache(element, name, observer, useCapture);
+ },
+
+ stopObserving: function(element, name, observer, useCapture) {
+ element = $(element);
+ useCapture = useCapture || false;
+
+ if (name == 'keypress' &&
+ (navigator.appVersion.match(/Konqueror|Safari|KHTML/)
+ || element.detachEvent))
+ name = 'keydown';
+
+ if (element.removeEventListener) {
+ element.removeEventListener(name, observer, useCapture);
+ } else if (element.detachEvent) {
+ try {
+ element.detachEvent('on' + name, observer);
+ } catch (e) {}
+ }
+ }
+});
+
+/* prevent memory leaks in IE */
+if (navigator.appVersion.match(/\bMSIE\b/))
+ Event.observe(window, 'unload', Event.unloadCache, false);
+var Position = {
+ // set to true if needed, warning: firefox performance problems
+ // NOT neeeded for page scrolling, only if draggable contained in
+ // scrollable elements
+ includeScrollOffsets: false,
+
+ // must be called before calling withinIncludingScrolloffset, every time the
+ // page is scrolled
+ prepare: function() {
+ this.deltaX = window.pageXOffset
+ || document.documentElement.scrollLeft
+ || document.body.scrollLeft
+ || 0;
+ this.deltaY = window.pageYOffset
+ || document.documentElement.scrollTop
+ || document.body.scrollTop
+ || 0;
+ },
+
+ realOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.scrollTop || 0;
+ valueL += element.scrollLeft || 0;
+ element = element.parentNode;
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ cumulativeOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ positionedOffset: function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ element = element.offsetParent;
+ if (element) {
+ if(element.tagName=='BODY') break;
+ var p = Element.getStyle(element, 'position');
+ if (p == 'relative' || p == 'absolute') break;
+ }
+ } while (element);
+ return [valueL, valueT];
+ },
+
+ offsetParent: function(element) {
+ if (element.offsetParent) return element.offsetParent;
+ if (element == document.body) return element;
+
+ while ((element = element.parentNode) && element != document.body)
+ if (Element.getStyle(element, 'position') != 'static')
+ return element;
+
+ return document.body;
+ },
+
+ // caches x/y coordinate pair to use with overlap
+ within: function(element, x, y) {
+ if (this.includeScrollOffsets)
+ return this.withinIncludingScrolloffsets(element, x, y);
+ this.xcomp = x;
+ this.ycomp = y;
+ this.offset = this.cumulativeOffset(element);
+
+ return (y >= this.offset[1] &&
+ y < this.offset[1] + element.offsetHeight &&
+ x >= this.offset[0] &&
+ x < this.offset[0] + element.offsetWidth);
+ },
+
+ withinIncludingScrolloffsets: function(element, x, y) {
+ var offsetcache = this.realOffset(element);
+
+ this.xcomp = x + offsetcache[0] - this.deltaX;
+ this.ycomp = y + offsetcache[1] - this.deltaY;
+ this.offset = this.cumulativeOffset(element);
+
+ return (this.ycomp >= this.offset[1] &&
+ this.ycomp < this.offset[1] + element.offsetHeight &&
+ this.xcomp >= this.offset[0] &&
+ this.xcomp < this.offset[0] + element.offsetWidth);
+ },
+
+ // within must be called directly before
+ overlap: function(mode, element) {
+ if (!mode) return 0;
+ if (mode == 'vertical')
+ return ((this.offset[1] + element.offsetHeight) - this.ycomp) /
+ element.offsetHeight;
+ if (mode == 'horizontal')
+ return ((this.offset[0] + element.offsetWidth) - this.xcomp) /
+ element.offsetWidth;
+ },
+
+ page: function(forElement) {
+ var valueT = 0, valueL = 0;
+
+ var element = forElement;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+
+ // Safari fix
+ if (element.offsetParent==document.body)
+ if (Element.getStyle(element,'position')=='absolute') break;
+
+ } while (element = element.offsetParent);
+
+ element = forElement;
+ do {
+ if (!window.opera || element.tagName=='BODY') {
+ valueT -= element.scrollTop || 0;
+ valueL -= element.scrollLeft || 0;
+ }
+ } while (element = element.parentNode);
+
+ return [valueL, valueT];
+ },
+
+ clone: function(source, target) {
+ var options = Object.extend({
+ setLeft: true,
+ setTop: true,
+ setWidth: true,
+ setHeight: true,
+ offsetTop: 0,
+ offsetLeft: 0
+ }, arguments[2] || {})
+
+ // find page position of source
+ source = $(source);
+ var p = Position.page(source);
+
+ // find coordinate system to use
+ target = $(target);
+ var delta = [0, 0];
+ var parent = null;
+ // delta [0,0] will do fine with position: fixed elements,
+ // position:absolute needs offsetParent deltas
+ if (Element.getStyle(target,'position') == 'absolute') {
+ parent = Position.offsetParent(target);
+ delta = Position.page(parent);
+ }
+
+ // correct by body offsets (fixes Safari)
+ if (parent == document.body) {
+ delta[0] -= document.body.offsetLeft;
+ delta[1] -= document.body.offsetTop;
+ }
+
+ // set position
+ if(options.setLeft) target.style.left = (p[0] - delta[0] + options.offsetLeft) + 'px';
+ if(options.setTop) target.style.top = (p[1] - delta[1] + options.offsetTop) + 'px';
+ if(options.setWidth) target.style.width = source.offsetWidth + 'px';
+ if(options.setHeight) target.style.height = source.offsetHeight + 'px';
+ },
+
+ absolutize: function(element) {
+ element = $(element);
+ if (element.style.position == 'absolute') return;
+ Position.prepare();
+
+ var offsets = Position.positionedOffset(element);
+ var top = offsets[1];
+ var left = offsets[0];
+ var width = element.clientWidth;
+ var height = element.clientHeight;
+
+ element._originalLeft = left - parseFloat(element.style.left || 0);
+ element._originalTop = top - parseFloat(element.style.top || 0);
+ element._originalWidth = element.style.width;
+ element._originalHeight = element.style.height;
+
+ element.style.position = 'absolute';
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.width = width + 'px';
+ element.style.height = height + 'px';
+ },
+
+ relativize: function(element) {
+ element = $(element);
+ if (element.style.position == 'relative') return;
+ Position.prepare();
+
+ element.style.position = 'relative';
+ var top = parseFloat(element.style.top || 0) - (element._originalTop || 0);
+ var left = parseFloat(element.style.left || 0) - (element._originalLeft || 0);
+
+ element.style.top = top + 'px';
+ element.style.left = left + 'px';
+ element.style.height = element._originalHeight;
+ element.style.width = element._originalWidth;
+ }
+}
+
+// Safari returns margins on body which is incorrect if the child is absolutely
+// positioned. For performance reasons, redefine Position.cumulativeOffset for
+// KHTML/WebKit only.
+if (/Konqueror|Safari|KHTML/.test(navigator.userAgent)) {
+ Position.cumulativeOffset = function(element) {
+ var valueT = 0, valueL = 0;
+ do {
+ valueT += element.offsetTop || 0;
+ valueL += element.offsetLeft || 0;
+ if (element.offsetParent == document.body)
+ if (Element.getStyle(element, 'position') == 'absolute') break;
+
+ element = element.offsetParent;
+ } while (element);
+
+ return [valueL, valueT];
+ }
+}
+
+Element.addMethods();
\ No newline at end of file
diff --git a/web/log/merb.4000.pid b/web/log/merb.4000.pid
new file mode 100644
index 000000000..52b85a992
--- /dev/null
+++ b/web/log/merb.4000.pid
@@ -0,0 +1 @@
+31261
\ No newline at end of file
diff --git a/web/merb/merb-auth/setup.rb b/web/merb/merb-auth/setup.rb
new file mode 100644
index 000000000..612f01d5a
--- /dev/null
+++ b/web/merb/merb-auth/setup.rb
@@ -0,0 +1,44 @@
+# This file is specifically setup for use with the merb-auth plugin.
+# This file should be used to setup and configure your authentication stack.
+# It is not required and may safely be deleted.
+#
+# To change the parameter names for the password or login field you may set either of these two options
+#
+# Merb::Plugins.config[:"merb-auth"][:login_param] = :email
+# Merb::Plugins.config[:"merb-auth"][:password_param] = :my_password_field_name
+
+begin
+ # Sets the default class ofr authentication. This is primarily used for
+ # Plugins and the default strategies
+ Merb::Authentication.user_class = User
+
+
+ # Mixin the salted user mixin
+ require 'merb-auth-more/mixins/salted_user'
+ Merb::Authentication.user_class.class_eval{ include Merb::Authentication::Mixins::SaltedUser }
+
+ # Setup the session serialization
+ class Merb::Authentication
+
+ def fetch_user(session_user_id)
+ Merb::Authentication.user_class.get(session_user_id)
+ end
+
+ def store_user(user)
+ user.nil? ? user : user.id
+ end
+ end
+
+rescue
+ Merb.logger.error <<-TEXT
+
+ You need to setup some kind of user class with merb-auth.
+ Merb::Authentication.user_class = User
+
+ If you want to fully customize your authentication you should use merb-core directly.
+
+ See merb/merb-auth/setup.rb and strategies.rb to customize your setup
+
+ TEXT
+end
+
diff --git a/web/merb/merb-auth/strategies.rb b/web/merb/merb-auth/strategies.rb
new file mode 100644
index 000000000..fd6f20a0c
--- /dev/null
+++ b/web/merb/merb-auth/strategies.rb
@@ -0,0 +1,11 @@
+# This file is specifically for you to define your strategies
+#
+# You should declare you strategies directly and/or use
+# Merb::Authentication.activate!(:label_of_strategy)
+#
+# To load and set the order of strategy processing
+
+Merb::Slices::config[:"merb-auth-slice-password"][:no_default_strategies] = true
+
+Merb::Authentication.activate!(:default_password_form)
+Merb::Authentication.activate!(:default_basic_auth)
\ No newline at end of file
diff --git a/web/merb/session/session.rb b/web/merb/session/session.rb
new file mode 100644
index 000000000..5d0531635
--- /dev/null
+++ b/web/merb/session/session.rb
@@ -0,0 +1,9 @@
+module Merb
+ module Session
+
+ # The Merb::Session module gets mixed into Merb::SessionContainer to allow
+ # app-level functionality; it will be included and methods will be available
+ # through request.session as instance methods.
+
+ end
+end
\ No newline at end of file
diff --git a/web/public/.htaccess b/web/public/.htaccess
new file mode 100644
index 000000000..455e706f9
--- /dev/null
+++ b/web/public/.htaccess
@@ -0,0 +1,17 @@
+# Sets the default handler for FastCGI scripts
+AddHandler fastcgi-script .fcgi
+
+# If Apache2 is used together with mod_fcgid,
+# uncomment the line below and comment in the line
+# above to set the correct script handler
+#AddHandler fcgid-script .fcgi
+
+RewriteEngine On
+
+RewriteRule ^$ index.html [QSA]
+RewriteRule ^([^.]+)$ $1.html [QSA]
+RewriteCond %{REQUEST_FILENAME} !-f
+RewriteRule ^(.*)$ merb.fcgi [QSA,L]
+
+
+ErrorDocument 500 "Application Error Merb could not be reached"
diff --git a/web/public/favicon.ico b/web/public/favicon.ico
new file mode 100644
index 000000000..c908d63b9
Binary files /dev/null and b/web/public/favicon.ico differ
diff --git a/web/public/images/merb.jpg b/web/public/images/merb.jpg
new file mode 100644
index 000000000..a19dcf404
Binary files /dev/null and b/web/public/images/merb.jpg differ
diff --git a/web/public/javascripts/application.js b/web/public/javascripts/application.js
new file mode 100644
index 000000000..246a8be4c
--- /dev/null
+++ b/web/public/javascripts/application.js
@@ -0,0 +1 @@
+// Common JavaScript code across your application goes here.
\ No newline at end of file
diff --git a/web/public/javascripts/jquery.js b/web/public/javascripts/jquery.js
new file mode 100644
index 000000000..396646c84
--- /dev/null
+++ b/web/public/javascripts/jquery.js
@@ -0,0 +1,19 @@
+/*
+ * jQuery JavaScript Library v1.3
+ * http://jquery.com/
+ *
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ *
+ * Date: 2009-01-13 12:50:31 -0500 (Tue, 13 Jan 2009)
+ * Revision: 6104
+ */
+(function(){var l=this,g,x=l.jQuery,o=l.$,n=l.jQuery=l.$=function(D,E){return new n.fn.init(D,E)},C=/^[^<]*(<(.|\s)+>)[^>]*$|^#([\w-]+)$/,f=/^.[^:#\[\.,]*$/;n.fn=n.prototype={init:function(D,G){D=D||document;if(D.nodeType){this[0]=D;this.length=1;this.context=D;return this}if(typeof D==="string"){var F=C.exec(D);if(F&&(F[1]||!G)){if(F[1]){D=n.clean([F[1]],G)}else{var H=document.getElementById(F[3]);if(H){if(H.id!=F[3]){return n().find(D)}var E=n(H);E.context=document;E.selector=D;return E}D=[]}}else{return n(G).find(D)}}else{if(n.isFunction(D)){return n(document).ready(D)}}if(D.selector&&D.context){this.selector=D.selector;this.context=D.context}return this.setArray(n.makeArray(D))},selector:"",jquery:"1.3",size:function(){return this.length},get:function(D){return D===g?n.makeArray(this):this[D]},pushStack:function(E,G,D){var F=n(E);F.prevObject=this;F.context=this.context;if(G==="find"){F.selector=this.selector+(this.selector?" ":"")+D}else{if(G){F.selector=this.selector+"."+G+"("+D+")"}}return F},setArray:function(D){this.length=0;Array.prototype.push.apply(this,D);return this},each:function(E,D){return n.each(this,E,D)},index:function(D){return n.inArray(D&&D.jquery?D[0]:D,this)},attr:function(E,G,F){var D=E;if(typeof E==="string"){if(G===g){return this[0]&&n[F||"attr"](this[0],E)}else{D={};D[E]=G}}return this.each(function(H){for(E in D){n.attr(F?this.style:this,E,n.prop(this,D[E],F,H,E))}})},css:function(D,E){if((D=="width"||D=="height")&&parseFloat(E)<0){E=g}return this.attr(D,E,"curCSS")},text:function(E){if(typeof E!=="object"&&E!=null){return this.empty().append((this[0]&&this[0].ownerDocument||document).createTextNode(E))}var D="";n.each(E||this,function(){n.each(this.childNodes,function(){if(this.nodeType!=8){D+=this.nodeType!=1?this.nodeValue:n.fn.text([this])}})});return D},wrapAll:function(D){if(this[0]){var E=n(D,this[0].ownerDocument).clone();if(this[0].parentNode){E.insertBefore(this[0])}E.map(function(){var F=this;while(F.firstChild){F=F.firstChild}return F}).append(this)}return this},wrapInner:function(D){return this.each(function(){n(this).contents().wrapAll(D)})},wrap:function(D){return this.each(function(){n(this).wrapAll(D)})},append:function(){return this.domManip(arguments,true,function(D){if(this.nodeType==1){this.appendChild(D)}})},prepend:function(){return this.domManip(arguments,true,function(D){if(this.nodeType==1){this.insertBefore(D,this.firstChild)}})},before:function(){return this.domManip(arguments,false,function(D){this.parentNode.insertBefore(D,this)})},after:function(){return this.domManip(arguments,false,function(D){this.parentNode.insertBefore(D,this.nextSibling)})},end:function(){return this.prevObject||n([])},push:[].push,find:function(D){if(this.length===1&&!/,/.test(D)){var F=this.pushStack([],"find",D);F.length=0;n.find(D,this[0],F);return F}else{var E=n.map(this,function(G){return n.find(D,G)});return this.pushStack(/[^+>] [^+>]/.test(D)?n.unique(E):E,"find",D)}},clone:function(E){var D=this.map(function(){if(!n.support.noCloneEvent&&!n.isXMLDoc(this)){var H=this.cloneNode(true),G=document.createElement("div");G.appendChild(H);return n.clean([G.innerHTML])[0]}else{return this.cloneNode(true)}});var F=D.find("*").andSelf().each(function(){if(this[h]!==g){this[h]=null}});if(E===true){this.find("*").andSelf().each(function(H){if(this.nodeType==3){return}var G=n.data(this,"events");for(var J in G){for(var I in G[J]){n.event.add(F[H],J,G[J][I],G[J][I].data)}}})}return D},filter:function(D){return this.pushStack(n.isFunction(D)&&n.grep(this,function(F,E){return D.call(F,E)})||n.multiFilter(D,n.grep(this,function(E){return E.nodeType===1})),"filter",D)},closest:function(D){var E=n.expr.match.POS.test(D)?n(D):null;return this.map(function(){var F=this;while(F&&F.ownerDocument){if(E?E.index(F)>-1:n(F).is(D)){return F}F=F.parentNode}})},not:function(D){if(typeof D==="string"){if(f.test(D)){return this.pushStack(n.multiFilter(D,this,true),"not",D)}else{D=n.multiFilter(D,this)}}var E=D.length&&D[D.length-1]!==g&&!D.nodeType;return this.filter(function(){return E?n.inArray(this,D)<0:this!=D})},add:function(D){return this.pushStack(n.unique(n.merge(this.get(),typeof D==="string"?n(D):n.makeArray(D))))},is:function(D){return !!D&&n.multiFilter(D,this).length>0},hasClass:function(D){return !!D&&this.is("."+D)},val:function(J){if(J===g){var D=this[0];if(D){if(n.nodeName(D,"option")){return(D.attributes.value||{}).specified?D.value:D.text}if(n.nodeName(D,"select")){var H=D.selectedIndex,K=[],L=D.options,G=D.type=="select-one";if(H<0){return null}for(var E=G?H:0,I=G?H+1:L.length;E=0||n.inArray(this.name,J)>=0)}else{if(n.nodeName(this,"select")){var M=n.makeArray(J);n("option",this).each(function(){this.selected=(n.inArray(this.value,M)>=0||n.inArray(this.text,M)>=0)});if(!M.length){this.selectedIndex=-1}}else{this.value=J}}})},html:function(D){return D===g?(this[0]?this[0].innerHTML:null):this.empty().append(D)},replaceWith:function(D){return this.after(D).remove()},eq:function(D){return this.slice(D,+D+1)},slice:function(){return this.pushStack(Array.prototype.slice.apply(this,arguments),"slice",Array.prototype.slice.call(arguments).join(","))},map:function(D){return this.pushStack(n.map(this,function(F,E){return D.call(F,E,F)}))},andSelf:function(){return this.add(this.prevObject)},domManip:function(J,M,L){if(this[0]){var I=(this[0].ownerDocument||this[0]).createDocumentFragment(),F=n.clean(J,(this[0].ownerDocument||this[0]),I),H=I.firstChild,D=this.length>1?I.cloneNode(true):I;if(H){for(var G=0,E=this.length;G0?D.cloneNode(true):I)}}if(F){n.each(F,y)}}return this;function K(N,O){return M&&n.nodeName(N,"table")&&n.nodeName(O,"tr")?(N.getElementsByTagName("tbody")[0]||N.appendChild(N.ownerDocument.createElement("tbody"))):N}}};n.fn.init.prototype=n.fn;function y(D,E){if(E.src){n.ajax({url:E.src,async:false,dataType:"script"})}else{n.globalEval(E.text||E.textContent||E.innerHTML||"")}if(E.parentNode){E.parentNode.removeChild(E)}}function e(){return +new Date}n.extend=n.fn.extend=function(){var I=arguments[0]||{},G=1,H=arguments.length,D=false,F;if(typeof I==="boolean"){D=I;I=arguments[1]||{};G=2}if(typeof I!=="object"&&!n.isFunction(I)){I={}}if(H==G){I=this;--G}for(;G-1}},swap:function(G,F,H){var D={};for(var E in F){D[E]=G.style[E];G.style[E]=F[E]}H.call(G);for(var E in F){G.style[E]=D[E]}},css:function(F,D,H){if(D=="width"||D=="height"){var J,E={position:"absolute",visibility:"hidden",display:"block"},I=D=="width"?["Left","Right"]:["Top","Bottom"];function G(){J=D=="width"?F.offsetWidth:F.offsetHeight;var L=0,K=0;n.each(I,function(){L+=parseFloat(n.curCSS(F,"padding"+this,true))||0;K+=parseFloat(n.curCSS(F,"border"+this+"Width",true))||0});J-=Math.round(L+K)}if(n(F).is(":visible")){G()}else{n.swap(F,E,G)}return Math.max(0,J)}return n.curCSS(F,D,H)},curCSS:function(H,E,F){var K,D=H.style;if(E=="opacity"&&!n.support.opacity){K=n.attr(D,"opacity");return K==""?"1":K}if(E.match(/float/i)){E=v}if(!F&&D&&D[E]){K=D[E]}else{if(p.getComputedStyle){if(E.match(/float/i)){E="float"}E=E.replace(/([A-Z])/g,"-$1").toLowerCase();var L=p.getComputedStyle(H,null);if(L){K=L.getPropertyValue(E)}if(E=="opacity"&&K==""){K="1"}}else{if(H.currentStyle){var I=E.replace(/\-(\w)/g,function(M,N){return N.toUpperCase()});K=H.currentStyle[E]||H.currentStyle[I];if(!/^\d+(px)?$/i.test(K)&&/^\d/.test(K)){var G=D.left,J=H.runtimeStyle.left;H.runtimeStyle.left=H.currentStyle.left;D.left=K||0;K=D.pixelLeft+"px";D.left=G;H.runtimeStyle.left=J}}}}return K},clean:function(E,J,H){J=J||document;if(typeof J.createElement==="undefined"){J=J.ownerDocument||J[0]&&J[0].ownerDocument||document}if(!H&&E.length===1&&typeof E[0]==="string"){var G=/^<(\w+)\s*\/?>$/.exec(E[0]);if(G){return[J.createElement(G[1])]}}var F=[],D=[],K=J.createElement("div");n.each(E,function(O,Q){if(typeof Q==="number"){Q+=""}if(!Q){return}if(typeof Q==="string"){Q=Q.replace(/(<(\w+)[^>]*?)\/>/g,function(S,T,R){return R.match(/^(abbr|br|col|img|input|link|meta|param|hr|area|embed)$/i)?S:T+">"+R+">"});var N=n.trim(Q).toLowerCase();var P=!N.indexOf("",""]||!N.indexOf("",""]||N.match(/^<(thead|tbody|tfoot|colg|cap)/)&&[1,""]||!N.indexOf(""," "]||(!N.indexOf(""," "]||!N.indexOf(""," "]||!n.support.htmlSerialize&&[1,"div","
"]||[0,"",""];K.innerHTML=P[1]+Q+P[2];while(P[0]--){K=K.lastChild}if(!n.support.tbody){var M=!N.indexOf(""&&N.indexOf("=0;--L){if(n.nodeName(M[L],"tbody")&&!M[L].childNodes.length){M[L].parentNode.removeChild(M[L])}}}if(!n.support.leadingWhitespace&&/^\s/.test(Q)){K.insertBefore(J.createTextNode(Q.match(/^\s*/)[0]),K.firstChild)}Q=n.makeArray(K.childNodes)}if(Q.nodeType){F.push(Q)}else{F=n.merge(F,Q)}});if(H){for(var I=0;F[I];I++){if(n.nodeName(F[I],"script")&&(!F[I].type||F[I].type.toLowerCase()==="text/javascript")){D.push(F[I].parentNode?F[I].parentNode.removeChild(F[I]):F[I])}else{if(F[I].nodeType===1){F.splice.apply(F,[I+1,0].concat(n.makeArray(F[I].getElementsByTagName("script"))))}H.appendChild(F[I])}}return D}return F},attr:function(I,F,J){if(!I||I.nodeType==3||I.nodeType==8){return g}var G=!n.isXMLDoc(I),K=J!==g;F=G&&n.props[F]||F;if(I.tagName){var E=/href|src|style/.test(F);if(F=="selected"&&I.parentNode){I.parentNode.selectedIndex}if(F in I&&G&&!E){if(K){if(F=="type"&&n.nodeName(I,"input")&&I.parentNode){throw"type property can't be changed"}I[F]=J}if(n.nodeName(I,"form")&&I.getAttributeNode(F)){return I.getAttributeNode(F).nodeValue}if(F=="tabIndex"){var H=I.getAttributeNode("tabIndex");return H&&H.specified?H.value:I.nodeName.match(/^(a|area|button|input|object|select|textarea)$/i)?0:g}return I[F]}if(!n.support.style&&G&&F=="style"){return n.attr(I.style,"cssText",J)}if(K){I.setAttribute(F,""+J)}var D=!n.support.hrefNormalized&&G&&E?I.getAttribute(F,2):I.getAttribute(F);return D===null?g:D}if(!n.support.opacity&&F=="opacity"){if(K){I.zoom=1;I.filter=(I.filter||"").replace(/alpha\([^)]*\)/,"")+(parseInt(J)+""=="NaN"?"":"alpha(opacity="+J*100+")")}return I.filter&&I.filter.indexOf("opacity=")>=0?(parseFloat(I.filter.match(/opacity=([^)]*)/)[1])/100)+"":""}F=F.replace(/-([a-z])/ig,function(L,M){return M.toUpperCase()});if(K){I[F]=J}return I[F]},trim:function(D){return(D||"").replace(/^\s+|\s+$/g,"")},makeArray:function(F){var D=[];if(F!=null){var E=F.length;if(E==null||typeof F==="string"||n.isFunction(F)||F.setInterval){D[0]=F}else{while(E){D[--E]=F[E]}}}return D},inArray:function(F,G){for(var D=0,E=G.length;D*",this).remove();while(this.firstChild){this.removeChild(this.firstChild)}}},function(D,E){n.fn[D]=function(){return this.each(E,arguments)}});function j(D,E){return D[0]&&parseInt(n.curCSS(D[0],E,true),10)||0}var h="jQuery"+e(),u=0,z={};n.extend({cache:{},data:function(E,D,F){E=E==l?z:E;var G=E[h];if(!G){G=E[h]=++u}if(D&&!n.cache[G]){n.cache[G]={}}if(F!==g){n.cache[G][D]=F}return D?n.cache[G][D]:G},removeData:function(E,D){E=E==l?z:E;var G=E[h];if(D){if(n.cache[G]){delete n.cache[G][D];D="";for(D in n.cache[G]){break}if(!D){n.removeData(E)}}}else{try{delete E[h]}catch(F){if(E.removeAttribute){E.removeAttribute(h)}}delete n.cache[G]}},queue:function(E,D,G){if(E){D=(D||"fx")+"queue";var F=n.data(E,D);if(!F||n.isArray(G)){F=n.data(E,D,n.makeArray(G))}else{if(G){F.push(G)}}}return F},dequeue:function(G,F){var D=n.queue(G,F),E=D.shift();if(!F||F==="fx"){E=D[0]}if(E!==g){E.call(G)}}});n.fn.extend({data:function(D,F){var G=D.split(".");G[1]=G[1]?"."+G[1]:"";if(F===g){var E=this.triggerHandler("getData"+G[1]+"!",[G[0]]);if(E===g&&this.length){E=n.data(this[0],D)}return E===g&&G[1]?this.data(G[0]):E}else{return this.trigger("setData"+G[1]+"!",[G[0],F]).each(function(){n.data(this,D,F)})}},removeData:function(D){return this.each(function(){n.removeData(this,D)})},queue:function(D,E){if(typeof D!=="string"){E=D;D="fx"}if(E===g){return n.queue(this[0],D)}return this.each(function(){var F=n.queue(this,D,E);if(D=="fx"&&F.length==1){F[0].call(this)}})},dequeue:function(D){return this.each(function(){n.dequeue(this,D)})}});
+/*
+ * Sizzle CSS Selector Engine - v0.9.1
+ * Copyright 2009, The Dojo Foundation
+ * Released under the MIT, BSD, and GPL Licenses.
+ * More information: http://sizzlejs.com/
+ */
+(function(){var N=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|[^[\]]+)+\]|\\.|[^ >+~,(\[]+)+|[>+~])(\s*,\s*)?/g,I=0,F=Object.prototype.toString;var E=function(ae,S,aa,V){aa=aa||[];S=S||document;if(S.nodeType!==1&&S.nodeType!==9){return[]}if(!ae||typeof ae!=="string"){return aa}var ab=[],ac,Y,ah,ag,Z,R,Q=true;N.lastIndex=0;while((ac=N.exec(ae))!==null){ab.push(ac[1]);if(ac[2]){R=RegExp.rightContext;break}}if(ab.length>1&&G.match.POS.exec(ae)){if(ab.length===2&&G.relative[ab[0]]){var U="",X;while((X=G.match.POS.exec(ae))){U+=X[0];ae=ae.replace(G.match.POS,"")}Y=E.filter(U,E(/\s$/.test(ae)?ae+"*":ae,S))}else{Y=G.relative[ab[0]]?[S]:E(ab.shift(),S);while(ab.length){var P=[];ae=ab.shift();if(G.relative[ae]){ae+=ab.shift()}for(var af=0,ad=Y.length;af0){ah=D(Y)}else{Q=false}while(ab.length){var T=ab.pop(),W=T;if(!G.relative[T]){T=""}else{W=ab.pop()}if(W==null){W=S}G.relative[T](ah,W,M(S))}}if(!ah){ah=Y}if(!ah){throw"Syntax error, unrecognized expression: "+(T||ae)}if(F.call(ah)==="[object Array]"){if(!Q){aa.push.apply(aa,ah)}else{if(S.nodeType===1){for(var af=0;ah[af]!=null;af++){if(ah[af]&&(ah[af]===true||ah[af].nodeType===1&&H(S,ah[af]))){aa.push(Y[af])}}}else{for(var af=0;ah[af]!=null;af++){if(ah[af]&&ah[af].nodeType===1){aa.push(Y[af])}}}}}else{D(ah,aa)}if(R){E(R,S,aa,V)}return aa};E.matches=function(P,Q){return E(P,null,null,Q)};E.find=function(V,S){var W,Q;if(!V){return[]}for(var R=0,P=G.order.length;R":function(U,Q,V){if(typeof Q==="string"&&!/\W/.test(Q)){Q=V?Q:Q.toUpperCase();for(var R=0,P=U.length;R
=0){if(!R){P.push(Q[T])}}else{if(R){Q[T]=false}}}return false},ID:function(P){return P[1].replace(/\\/g,"")},TAG:function(Q,P){for(var R=0;!P[R];R++){}return M(P[R])?Q[1]:Q[1].toUpperCase()},CHILD:function(P){if(P[1]=="nth"){var Q=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(P[2]=="even"&&"2n"||P[2]=="odd"&&"2n+1"||!/\D/.test(P[2])&&"0n+"+P[2]||P[2]);P[2]=(Q[1]+(Q[2]||1))-0;P[3]=Q[3]-0}P[0]="done"+(I++);return P},ATTR:function(Q){var P=Q[1];if(G.attrMap[P]){Q[1]=G.attrMap[P]}if(Q[2]==="~="){Q[4]=" "+Q[4]+" "}return Q},PSEUDO:function(T,Q,R,P,U){if(T[1]==="not"){if(T[3].match(N).length>1){T[3]=E(T[3],null,null,Q)}else{var S=E.filter(T[3],Q,R,true^U);if(!R){P.push.apply(P,S)}return false}}else{if(G.match.POS.test(T[0])){return true}}return T},POS:function(P){P.unshift(true);return P}},filters:{enabled:function(P){return P.disabled===false&&P.type!=="hidden"},disabled:function(P){return P.disabled===true},checked:function(P){return P.checked===true},selected:function(P){P.parentNode.selectedIndex;return P.selected===true},parent:function(P){return !!P.firstChild},empty:function(P){return !P.firstChild},has:function(R,Q,P){return !!E(P[3],R).length},header:function(P){return/h\d/i.test(P.nodeName)},text:function(P){return"text"===P.type},radio:function(P){return"radio"===P.type},checkbox:function(P){return"checkbox"===P.type},file:function(P){return"file"===P.type},password:function(P){return"password"===P.type},submit:function(P){return"submit"===P.type},image:function(P){return"image"===P.type},reset:function(P){return"reset"===P.type},button:function(P){return"button"===P.type||P.nodeName.toUpperCase()==="BUTTON"},input:function(P){return/input|select|textarea|button/i.test(P.nodeName)}},setFilters:{first:function(Q,P){return P===0},last:function(R,Q,P,S){return Q===S.length-1},even:function(Q,P){return P%2===0},odd:function(Q,P){return P%2===1},lt:function(R,Q,P){return Q
P[3]-0},nth:function(R,Q,P){return P[3]-0==Q},eq:function(R,Q,P){return P[3]-0==Q}},filter:{CHILD:function(P,S){var V=S[1],W=P.parentNode;var U="child"+W.childNodes.length;if(W&&(!W[U]||!P.nodeIndex)){var T=1;for(var Q=W.firstChild;Q;Q=Q.nextSibling){if(Q.nodeType==1){Q.nodeIndex=T++}}W[U]=T-1}if(V=="first"){return P.nodeIndex==1}else{if(V=="last"){return P.nodeIndex==W[U]}else{if(V=="only"){return W[U]==1}else{if(V=="nth"){var Y=false,R=S[2],X=S[3];if(R==1&&X==0){return true}if(R==0){if(P.nodeIndex==X){Y=true}}else{if((P.nodeIndex-X)%R==0&&(P.nodeIndex-X)/R>=0){Y=true}}return Y}}}}},PSEUDO:function(V,R,S,W){var Q=R[1],T=G.filters[Q];if(T){return T(V,S,R,W)}else{if(Q==="contains"){return(V.textContent||V.innerText||"").indexOf(R[3])>=0}else{if(Q==="not"){var U=R[3];for(var S=0,P=U.length;S
=0:S==="~="?(" "+U+" ").indexOf(Q)>=0:!R[4]?P:S==="!="?U!=Q:S==="^="?U.indexOf(Q)===0:S==="$="?U.substr(U.length-Q.length)===Q:S==="|="?U===Q||U.substr(0,Q.length+1)===Q+"-":false},POS:function(T,Q,R,U){var P=Q[2],S=G.setFilters[P];if(S){return S(T,R,Q,U)}}}};for(var K in G.match){G.match[K]=RegExp(G.match[K].source+/(?![^\[]*\])(?![^\(]*\))/.source)}var D=function(Q,P){Q=Array.prototype.slice.call(Q);if(P){P.push.apply(P,Q);return P}return Q};try{Array.prototype.slice.call(document.documentElement.childNodes)}catch(J){D=function(T,S){var Q=S||[];if(F.call(T)==="[object Array]"){Array.prototype.push.apply(Q,T)}else{if(typeof T.length==="number"){for(var R=0,P=T.length;R
";var P=document.documentElement;P.insertBefore(Q,P.firstChild);if(!!document.getElementById(R)){G.find.ID=function(T,U){if(U.getElementById){var S=U.getElementById(T[1]);return S?S.id===T[1]||S.getAttributeNode&&S.getAttributeNode("id").nodeValue===T[1]?[S]:g:[]}};G.filter.ID=function(U,S){var T=U.getAttributeNode&&U.getAttributeNode("id");return U.nodeType===1&&T&&T.nodeValue===S}}P.removeChild(Q)})();(function(){var P=document.createElement("div");P.appendChild(document.createComment(""));if(P.getElementsByTagName("*").length>0){G.find.TAG=function(Q,U){var T=U.getElementsByTagName(Q[1]);if(Q[1]==="*"){var S=[];for(var R=0;T[R];R++){if(T[R].nodeType===1){S.push(T[R])}}T=S}return T}}P.innerHTML=" ";if(P.firstChild.getAttribute("href")!=="#"){G.attrHandle.href=function(Q){return Q.getAttribute("href",2)}}})();if(document.querySelectorAll){(function(){var P=E;E=function(T,S,Q,R){S=S||document;if(!R&&S.nodeType===9){try{return D(S.querySelectorAll(T),Q)}catch(U){}}return P(T,S,Q,R)};E.find=P.find;E.filter=P.filter;E.selectors=P.selectors;E.matches=P.matches})()}if(document.documentElement.getElementsByClassName){G.order.splice(1,0,"CLASS");G.find.CLASS=function(P,Q){return Q.getElementsByClassName(P[1])}}function L(Q,W,V,Z,X,Y){for(var T=0,R=Z.length;T0){T=P;break}}}P=P[Q]}Y[S]=T}}}var H=document.compareDocumentPosition?function(Q,P){return Q.compareDocumentPosition(P)&16}:function(Q,P){return Q!==P&&(Q.contains?Q.contains(P):true)};var M=function(P){return P.documentElement&&!P.body||P.tagName&&P.ownerDocument&&!P.ownerDocument.body};n.find=E;n.filter=E.filter;n.expr=E.selectors;n.expr[":"]=n.expr.filters;E.selectors.filters.hidden=function(P){return"hidden"===P.type||n.css(P,"display")==="none"||n.css(P,"visibility")==="hidden"};E.selectors.filters.visible=function(P){return"hidden"!==P.type&&n.css(P,"display")!=="none"&&n.css(P,"visibility")!=="hidden"};E.selectors.filters.animated=function(P){return n.grep(n.timers,function(Q){return P===Q.elem}).length};n.multiFilter=function(R,P,Q){if(Q){R=":not("+R+")"}return E.matches(R,P)};n.dir=function(R,Q){var P=[],S=R[Q];while(S&&S!=document){if(S.nodeType==1){P.push(S)}S=S[Q]}return P};n.nth=function(T,P,R,S){P=P||1;var Q=0;for(;T;T=T[R]){if(T.nodeType==1&&++Q==P){break}}return T};n.sibling=function(R,Q){var P=[];for(;R;R=R.nextSibling){if(R.nodeType==1&&R!=Q){P.push(R)}}return P};return;l.Sizzle=E})();n.event={add:function(H,E,G,J){if(H.nodeType==3||H.nodeType==8){return}if(H.setInterval&&H!=l){H=l}if(!G.guid){G.guid=this.guid++}if(J!==g){var F=G;G=this.proxy(F);G.data=J}var D=n.data(H,"events")||n.data(H,"events",{}),I=n.data(H,"handle")||n.data(H,"handle",function(){return typeof n!=="undefined"&&!n.event.triggered?n.event.handle.apply(arguments.callee.elem,arguments):g});I.elem=H;n.each(E.split(/\s+/),function(L,M){var N=M.split(".");M=N.shift();G.type=N.slice().sort().join(".");var K=D[M];if(n.event.specialAll[M]){n.event.specialAll[M].setup.call(H,J,N)}if(!K){K=D[M]={};if(!n.event.special[M]||n.event.special[M].setup.call(H,J,N)===false){if(H.addEventListener){H.addEventListener(M,I,false)}else{if(H.attachEvent){H.attachEvent("on"+M,I)}}}}K[G.guid]=G;n.event.global[M]=true});H=null},guid:1,global:{},remove:function(J,G,I){if(J.nodeType==3||J.nodeType==8){return}var F=n.data(J,"events"),E,D;if(F){if(G===g||(typeof G==="string"&&G.charAt(0)==".")){for(var H in F){this.remove(J,H+(G||""))}}else{if(G.type){I=G.handler;G=G.type}n.each(G.split(/\s+/),function(L,N){var P=N.split(".");N=P.shift();var M=RegExp("(^|\\.)"+P.slice().sort().join(".*\\.")+"(\\.|$)");if(F[N]){if(I){delete F[N][I.guid]}else{for(var O in F[N]){if(M.test(F[N][O].type)){delete F[N][O]}}}if(n.event.specialAll[N]){n.event.specialAll[N].teardown.call(J,P)}for(E in F[N]){break}if(!E){if(!n.event.special[N]||n.event.special[N].teardown.call(J,P)===false){if(J.removeEventListener){J.removeEventListener(N,n.data(J,"handle"),false)}else{if(J.detachEvent){J.detachEvent("on"+N,n.data(J,"handle"))}}}E=null;delete F[N]}}})}for(E in F){break}if(!E){var K=n.data(J,"handle");if(K){K.elem=null}n.removeData(J,"events");n.removeData(J,"handle")}}},trigger:function(H,J,G,D){var F=H.type||H;if(!D){H=typeof H==="object"?H[h]?H:n.extend(n.Event(F),H):n.Event(F);if(F.indexOf("!")>=0){H.type=F=F.slice(0,-1);H.exclusive=true}if(!G){H.stopPropagation();if(this.global[F]){n.each(n.cache,function(){if(this.events&&this.events[F]){n.event.trigger(H,J,this.handle.elem)}})}}if(!G||G.nodeType==3||G.nodeType==8){return g}H.result=g;H.target=G;J=n.makeArray(J);J.unshift(H)}H.currentTarget=G;var I=n.data(G,"handle");if(I){I.apply(G,J)}if((!G[F]||(n.nodeName(G,"a")&&F=="click"))&&G["on"+F]&&G["on"+F].apply(G,J)===false){H.result=false}if(!D&&G[F]&&!H.isDefaultPrevented()&&!(n.nodeName(G,"a")&&F=="click")){this.triggered=true;try{G[F]()}catch(K){}}this.triggered=false;if(!H.isPropagationStopped()){var E=G.parentNode||G.ownerDocument;if(E){n.event.trigger(H,J,E,true)}}},handle:function(J){var I,D;J=arguments[0]=n.event.fix(J||l.event);var K=J.type.split(".");J.type=K.shift();I=!K.length&&!J.exclusive;var H=RegExp("(^|\\.)"+K.slice().sort().join(".*\\.")+"(\\.|$)");D=(n.data(this,"events")||{})[J.type];for(var F in D){var G=D[F];if(I||H.test(G.type)){J.handler=G;J.data=G.data;var E=G.apply(this,arguments);if(E!==g){J.result=E;if(E===false){J.preventDefault();J.stopPropagation()}}if(J.isImmediatePropagationStopped()){break}}}},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode metaKey newValue originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "),fix:function(G){if(G[h]){return G}var E=G;G=n.Event(E);for(var F=this.props.length,I;F;){I=this.props[--F];G[I]=E[I]}if(!G.target){G.target=G.srcElement||document}if(G.target.nodeType==3){G.target=G.target.parentNode}if(!G.relatedTarget&&G.fromElement){G.relatedTarget=G.fromElement==G.target?G.toElement:G.fromElement}if(G.pageX==null&&G.clientX!=null){var H=document.documentElement,D=document.body;G.pageX=G.clientX+(H&&H.scrollLeft||D&&D.scrollLeft||0)-(H.clientLeft||0);G.pageY=G.clientY+(H&&H.scrollTop||D&&D.scrollTop||0)-(H.clientTop||0)}if(!G.which&&((G.charCode||G.charCode===0)?G.charCode:G.keyCode)){G.which=G.charCode||G.keyCode}if(!G.metaKey&&G.ctrlKey){G.metaKey=G.ctrlKey}if(!G.which&&G.button){G.which=(G.button&1?1:(G.button&2?3:(G.button&4?2:0)))}return G},proxy:function(E,D){D=D||function(){return E.apply(this,arguments)};D.guid=E.guid=E.guid||D.guid||this.guid++;return D},special:{ready:{setup:A,teardown:function(){}}},specialAll:{live:{setup:function(D,E){n.event.add(this,E[0],c)},teardown:function(F){if(F.length){var D=0,E=RegExp("(^|\\.)"+F[0]+"(\\.|$)");n.each((n.data(this,"events").live||{}),function(){if(E.test(this.type)){D++}});if(D<1){n.event.remove(this,F[0],c)}}}}}};n.Event=function(D){if(!this.preventDefault){return new n.Event(D)}if(D&&D.type){this.originalEvent=D;this.type=D.type;this.timeStamp=D.timeStamp}else{this.type=D}if(!this.timeStamp){this.timeStamp=e()}this[h]=true};function k(){return false}function t(){return true}n.Event.prototype={preventDefault:function(){this.isDefaultPrevented=t;var D=this.originalEvent;if(!D){return}if(D.preventDefault){D.preventDefault()}D.returnValue=false},stopPropagation:function(){this.isPropagationStopped=t;var D=this.originalEvent;if(!D){return}if(D.stopPropagation){D.stopPropagation()}D.cancelBubble=true},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=t;this.stopPropagation()},isDefaultPrevented:k,isPropagationStopped:k,isImmediatePropagationStopped:k};var a=function(E){var D=E.relatedTarget;while(D&&D!=this){try{D=D.parentNode}catch(F){D=this}}if(D!=this){E.type=E.data;n.event.handle.apply(this,arguments)}};n.each({mouseover:"mouseenter",mouseout:"mouseleave"},function(E,D){n.event.special[D]={setup:function(){n.event.add(this,E,a,D)},teardown:function(){n.event.remove(this,E,a)}}});n.fn.extend({bind:function(E,F,D){return E=="unload"?this.one(E,F,D):this.each(function(){n.event.add(this,E,D||F,D&&F)})},one:function(F,G,E){var D=n.event.proxy(E||G,function(H){n(this).unbind(H,D);return(E||G).apply(this,arguments)});return this.each(function(){n.event.add(this,F,D,E&&G)})},unbind:function(E,D){return this.each(function(){n.event.remove(this,E,D)})},trigger:function(D,E){return this.each(function(){n.event.trigger(D,E,this)})},triggerHandler:function(D,F){if(this[0]){var E=n.Event(D);E.preventDefault();E.stopPropagation();n.event.trigger(E,F,this[0]);return E.result}},toggle:function(F){var D=arguments,E=1;while(Ea text ';var G=J.getElementsByTagName("*"),D=J.getElementsByTagName("a")[0];if(!G||!G.length||!D){return}n.support={leadingWhitespace:J.firstChild.nodeType==3,tbody:!J.getElementsByTagName("tbody").length,objectAll:!!J.getElementsByTagName("object")[0].getElementsByTagName("*").length,htmlSerialize:!!J.getElementsByTagName("link").length,style:/red/.test(D.getAttribute("style")),hrefNormalized:D.getAttribute("href")==="/a",opacity:D.style.opacity==="0.5",cssFloat:!!D.style.cssFloat,scriptEval:false,noCloneEvent:true,boxModel:null};F.type="text/javascript";try{F.appendChild(document.createTextNode("window."+I+"=1;"))}catch(H){}E.insertBefore(F,E.firstChild);if(l[I]){n.support.scriptEval=true;delete l[I]}E.removeChild(F);if(J.attachEvent&&J.fireEvent){J.attachEvent("onclick",function(){n.support.noCloneEvent=false;J.detachEvent("onclick",arguments.callee)});J.cloneNode(true).fireEvent("onclick")}n(function(){var K=document.createElement("div");K.style.width="1px";K.style.paddingLeft="1px";document.body.appendChild(K);n.boxModel=n.support.boxModel=K.offsetWidth===2;document.body.removeChild(K)})})();var v=n.support.cssFloat?"cssFloat":"styleFloat";n.props={"for":"htmlFor","class":"className","float":v,cssFloat:v,styleFloat:v,readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",tabindex:"tabIndex"};n.fn.extend({_load:n.fn.load,load:function(F,I,J){if(typeof F!=="string"){return this._load(F)}var H=F.indexOf(" ");if(H>=0){var D=F.slice(H,F.length);F=F.slice(0,H)}var G="GET";if(I){if(n.isFunction(I)){J=I;I=null}else{if(typeof I==="object"){I=n.param(I);G="POST"}}}var E=this;n.ajax({url:F,type:G,dataType:"html",data:I,complete:function(L,K){if(K=="success"||K=="notmodified"){E.html(D?n("
").append(L.responseText.replace(/