Changeset 241

Show
Ignore:
Timestamp:
05/26/07 17:46:30 (2 years ago)
Author:
e.@brainspl.at
Message:

CHange to the way Routing classes are setup. In your dist/conf/router.rb you must use Merb::Router.prepare instead of Merb::Routmatcher.prepare. Merb:Router:RouteGenerator added with support for fast route generation [dgoodland++]. I integrated the RouteGenerator? so normal usage of routes works the same for recognition, but now there is a way to generate routes as well. Added Merb::Controller#url helper for generating routes. Updated app skeleton. Fixed regex in router to not allow ;;; or /// when it only should only allow one of those chars in a row. Allow passing a symbol as well as an array to resources allowed methods list closes #48 thanks Zack

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/Rakefile

    r238 r241  
    1616 
    1717NAME = "merb" 
    18 VERS = "0.3.2
     18VERS = "0.3.3
    1919CLEAN.include ['**/.*.sw?', '*.gem', '.config'] 
    2020 
  • trunk/lib/merb.rb

    r238 r241  
    1616 
    1717module Merb 
    18   VERSION='0.3.2' unless defined?VERSION 
     18  VERSION='0.3.3' unless defined?VERSION 
    1919  class Server 
    2020    class << self 
  • trunk/lib/merb/merb_dispatcher.rb

    r225 r241  
    5050        path = path.sub(/\/+/, '/').sub(/\?.*$/, '') 
    5151        path = path[0..-2] if (path[-1] == ?/) && path.size > 1 
    52         Merb::RouteMatcher.route_request(path) 
     52        Merb::Router.match(path) 
    5353      end 
    5454       
  • trunk/lib/merb/merb_router.rb

    r240 r241  
    11module Merb 
    22 
    3   # Merb::RouteMatcher is the request routing mapper for the merb framework. 
    4   # You can define placeholder parts of the url with the :symbol notation. 
    5   # so r.add '/foo/:bar/baz/:id', :class => 'Bar', :method => 'foo' 
    6   # will match against a request to /foo/123/baz/456. It will then 
    7   # use the class Bar as your merb controller and call the foo method on it.  
    8   # the foo method will recieve a hash with {:bar => '123', :id => '456'} 
    9   # as the content. So the :placeholders sections of your routes become 
    10   # a hash of arguments to your controller methods. This route maps 
    11   # the default /controller/action and /controller/action/id urls: 
    12   # r.add '/:class/:method/:id' 
    13   class RouteMatcher 
    14      
    15     attr_accessor :sections 
    16     @@section_regexp = /(?::([a-z*_]+))/.freeze 
    17      
    18     # setup the router and yield it out to 
    19     # add routes to it. Then compile all routes 
    20     def self.prepare 
    21       @@routes = Array.new 
    22       @@compiled_statement = String.new 
    23       @@compiled_regexen = Array.new 
    24       yield self 
    25       compile_router 
    26     end   
    27  
    28     # the final compiled lambda that gets used 
    29     # as the body of the route_request method. 
    30     def self.compiled_statement 
    31       @@compiled_statement 
     3  class Router 
     4     
     5    SECTION_REGEXP = /(?::([a-z*_]+))/.freeze 
     6     
     7    class << self 
     8       
     9      def prepare(&block) 
     10        @@matcher = RouteMatcher.new 
     11        @@generator = RouteGenerator.new 
     12       
     13        yield self 
     14       
     15        @@matcher.compile_router 
     16      end 
     17       
     18      def add(*route) 
     19        @@matcher.add(*route) 
     20      end 
     21       
     22      def matcher 
     23        @@matcher 
     24      end 
     25       
     26      def generator 
     27        @@generator 
     28      end 
     29       
     30      def match(path) 
     31        @@matcher.route_request(path) 
     32      end 
     33       
     34      def generate(method, options = {}) 
     35        @@generator.generate(method, options) 
     36      end 
     37       
     38      def resources(res, opts={}) 
     39        opts[:prefix] ||= "" 
     40        if block_given? 
     41          procs = [] 
     42          yield Resource.new(res, procs, opts) 
     43          procs.reverse.each &:call 
     44        else 
     45          generate_resources_routes(res,opts) 
     46        end 
     47      end 
     48       
     49      def resource(res, opts={}) 
     50        opts[:prefix] ||= "" 
     51        if block_given? 
     52          procs = [] 
     53          yield Resource.new(res, procs, opts) 
     54          procs.reverse.each &:call 
     55        else 
     56          generate_singleton_routes(res,opts) 
     57        end 
     58      end 
     59       
     60      def default_routes 
     61        @@matcher.default_routes 
     62      end 
     63       
     64      def compiled_statement 
     65        @@matcher.compiled_statement 
     66      end 
     67       
     68      def compiled_regexen 
     69        @@matcher.compiled_regexen 
     70      end 
     71         
     72      def generate_resources_routes(res, opts) 
     73        @@matcher.generate_resources_routes(res, opts) 
     74        @@generator.generate_resources_routes(res, opts) 
     75      end 
     76       
     77      def generate_singleton_routes(res, opts) 
     78        @@matcher.generate_singleton_routes(res, opts) 
     79      end 
     80 
     81    end # class << self 
     82     
     83    # Merb::RouteMatcher is the request routing mapper for the merb framework. 
     84    # You can define placeholder parts of the url with the :symbol notation. 
     85    # so r.add '/foo/:bar/baz/:id', :class => 'Bar', :method => 'foo' 
     86    # will match against a request to /foo/123/baz/456. It will then 
     87    # use the class Bar as your merb controller and call the foo method on it.  
     88    # the foo method will recieve a hash with {:bar => '123', :id => '456'} 
     89    # as the content. So the :placeholders sections of your routes become 
     90    # a hash of arguments to your controller methods. This route maps 
     91    # the default /controller/action and /controller/action/id urls: 
     92    # r.add '/:class/:method/:id' 
     93    class RouteMatcher 
     94       
     95      attr_accessor :sections 
     96       
     97      def initialize 
     98        @routes = Array.new 
     99        @compiled_statement = String.new 
     100        @compiled_regexen   = Array.new 
     101      end 
     102 
     103      # the final compiled lambda that gets used 
     104      # as the body of the route_request method. 
     105      def compiled_statement 
     106        @compiled_statement 
     107      end 
     108       
     109      def compiled_regexen 
     110        @compiled_regexen 
     111      end 
     112       
     113      def compiled_statement 
     114        @compiled_statement 
     115      end 
     116     
     117      # add a route to be compiled 
     118      def add(*route) 
     119        @routes << [route[0], (route[1] || {})] 
     120      end 
     121       
     122      # build up a string that defines a lambda 
     123      # that does a case statement on the PATH_INFO 
     124      # against each of the compiled routes in turn. 
     125      # first route that matches wins. 
     126      def compile_router 
     127        router_lambda = @routes.inject("lambda{|path| \n  sections={}\n  case path\n") { |m,r| 
     128          m << compile(r) 
     129        } << "  else\n    return {:controller=>'Noroutefound', :action=>'noroute'}\n  end\n}" 
     130        @compiled_statement = router_lambda 
     131        meta_def(:route_request, &eval(router_lambda)) 
     132      end   
     133       
     134      # compile each individual route into a when /.../ 
     135      # component of the case statement. Takes /:sections 
     136      # of the route def that start with : and turns them 
     137      # into placeholders for whatever urls match against 
     138      # the route in question. 
     139      def compile(route) 
     140        raise ArgumentError unless String === route[0] 
     141        code, count = '', 0 
     142        while route[0] =~ SECTION_REGEXP 
     143          route[0] = route[0].dup 
     144          name = $1 
     145          (name =~ /(\*+)(\w+)/) ? (flag = true; name = $2) : (flag = false) 
     146          count += 1 
     147          if flag 
     148            route[0].sub!(Router::SECTION_REGEXP, "([^,?]+)") 
     149          else   
     150            route[0].sub!(Router::SECTION_REGEXP, "([^\/,?]+)") 
     151          end 
     152          code << "    sections[:#{name}] = $#{count}\n" 
     153        end 
     154        @compiled_regexen << Regexp.new(route[0]) 
     155        index = @compiled_regexen.size - 1 
     156        condition = "  when @compiled_regexen[#{index}] " 
     157        statement = "#{condition}\n#{code}" 
     158        statement << "    return #{route[1].inspect}.update(sections)\n" 
     159        statement 
     160      end 
     161       
     162      def generate_resources_routes(res,opt) 
     163        with_options :controller => res.to_s, :rest => true do |r| 
     164          r.add "#{opt[:prefix]}/#{res}/:id[;/]edit", :allowed => {:get => 'edit'} 
     165          r.add "#{opt[:prefix]}/#{res}/new[;/]:action", :allowed => {:get => 'new', :post => 'new', :put => 'new', :delete => 'new'} 
     166          r.add "#{opt[:prefix]}/#{res}/new" , :allowed => {:get => 'new'} 
     167          if mem = opt[:member] 
     168            mem.keys.sort_by{|x| "#{x}"}.each {|action| 
     169              allowed = mem[action].injecting({}) {|h, verb| h[verb] = "#{action}"} 
     170              r.add "#{opt[:prefix]}/#{res}/:id[;/]+#{action}", :allowed => allowed 
     171            } 
     172          end 
     173          if coll = opt[:collection] 
     174            coll.keys.sort_by{|x| "#{x}"}.each {|action| 
     175              allowed = coll[action].injecting({}) {|h, verb| h[verb] = "#{action}"} 
     176              r.add "#{opt[:prefix]}/#{res}[;/]#{action}", :allowed => allowed 
     177            } 
     178          end   
     179          r.add "#{opt[:prefix]}/#{res}/:id\\.:format", :allowed => {:get => 'show', :put => 'update', :delete => 'destroy'} 
     180          r.add "#{opt[:prefix]}/#{res}\\.:format", :allowed => {:get => 'index', :post => 'create'} 
     181          r.add "#{opt[:prefix]}/#{res}/:id", :allowed => {:get => 'show', :put => 'update', :delete => 'destroy'} 
     182          r.add "#{opt[:prefix]}/#{res}/?", :allowed => {:get => 'index', :post => 'create'} 
     183        end 
     184      end 
     185       
     186      def generate_singleton_routes(res,opt) 
     187        with_options :controller => res.to_s, :rest => true do |r| 
     188          r.add "#{opt[:prefix]}/#{res}[;/]edit", :allowed => {:get => 'edit'} 
     189          r.add "#{opt[:prefix]}/#{res}\\.:format", :allowed => {:get => 'show'} 
     190          r.add "#{opt[:prefix]}/#{res}/new" , :allowed => {:get => 'new'} 
     191          r.add "#{opt[:prefix]}/#{res}/?", :allowed => {:get => 'show', :post => 'create', :put => 'update', :delete => 'destroy'} 
     192        end 
     193      end 
     194       
     195      def default_routes 
     196        add "/:controller/:action/:id\\.:format" 
     197        add "/:controller/:action/:id" 
     198        add "/:controller/:action\\.:format" 
     199        add "/:controller/:action" 
     200        add "/:controller\\.:format", :action => 'index' 
     201        add "/:controller", :action => 'index' 
     202      end 
    32203    end 
    33      
    34     def self.compiled_regexen 
    35       @@compiled_regexen 
     204 
     205    class RouteGenerator 
     206 
     207      attr_accessor :paths 
     208 
     209      def initialize 
     210        @paths = {} 
     211      end 
     212 
     213      def add(name, path) 
     214        name = name.intern unless Symbol === name 
     215        @paths[name] = path 
     216      end 
     217 
     218      def generate(name, options = {}) 
     219        path = @paths[name] 
     220        while path =~ Router::SECTION_REGEXP 
     221          path.sub!(Router::SECTION_REGEXP, options[$~[1].intern].to_s) 
     222        end 
     223        path 
     224      end 
     225 
     226      def generate_resources_routes(res,opt) 
     227        res_singular = res.to_s.singularize 
     228        add res,                    "#{opt[:prefix]}/#{res}" 
     229        add res_singular,           "#{opt[:prefix]}/#{res}/:id" 
     230        add "new_#{res_singular}",  "#{opt[:prefix]}/#{res}/new" 
     231        add "edit_#{res_singular}", "#{opt[:prefix]}/#{res}/:id/edit" 
     232        #with_options :controller => res.to_s, :rest => true do |r| 
     233        #  r.add "#{opt[:prefix]}/#{res}/:id[;/]edit", :allowed => {:get => 'edit'} 
     234        #  r.add "#{opt[:prefix]}/#{res}/new[;/]:action", :allowed => {:get => 'new', :post => 'new', :put => 'new', :delete => 'new'} 
     235        #  r.add "#{opt[:prefix]}/#{res}/new" , :allowed => {:get => 'new'} 
     236        #  if mem = opt[:member] 
     237        #    mem.keys.sort_by{|x| "#{x}"}.each {|action| 
     238        #      allowed = mem[action].injecting({}) {|h, verb| h[verb] = "#{action}"} 
     239        #      r.add "#{opt[:prefix]}/#{res}/:id[;/]+#{action}", :allowed => allowed 
     240        #    } 
     241        #  end 
     242        #  if coll = opt[:collection] 
     243        #    coll.keys.sort_by{|x| "#{x}"}.each {|action| 
     244        #      allowed = coll[action].injecting({}) {|h, verb| h[verb] = "#{action}"} 
     245        #      r.add "#{opt[:prefix]}/#{res}[;/]#{action}", :allowed => allowed 
     246        #    } 
     247        #  end   
     248        #  r.add "#{opt[:prefix]}/#{res}/:id\\.:format", :allowed => {:get => 'show', :put => 'update', :delete => 'destroy'} 
     249        #  r.add "#{opt[:prefix]}/#{res}\\.:format", :allowed => {:get => 'index', :post => 'create'} 
     250        #  r.add "#{opt[:prefix]}/#{res}/:id", :allowed => {:get => 'show', :put => 'update', :delete => 'destroy'} 
     251        #  r.add "#{opt[:prefix]}/#{res}/?", :allowed => {:get => 'index', :post => 'create'} 
     252        #end 
     253      end 
    36254    end 
    37      
    38     def compiled_statement 
    39       @@compiled_statement 
    40     end 
    41    
    42     # add a route to be compiled 
    43     def self.add(*route) 
    44       @@routes << [route[0], (route[1] || {})] 
    45     end 
    46      
    47     # build up a string that defines a lambda 
    48     # that does a case statement on the PATH_INFO 
    49     # against each of the compiled routes in turn. 
    50     # first route that matches wins. 
    51     def self.compile_router 
    52       router_lambda = @@routes.inject("lambda{|path| \n  sections={}\n  case path\n") { |m,r| 
    53         m << compile(r) 
    54       } << "  else\n    return {:controller=>'Noroutefound', :action=>'noroute'}\n  end\n}" 
    55       @@compiled_statement = router_lambda 
    56       meta_def(:route_request, &eval(router_lambda)) 
    57     end   
    58      
    59     # compile each individual route into a when /.../ 
    60     # component of the case statement. Takes /:sections 
    61     # of the route def that start with : and turns them 
    62     # into placeholders for whatever urls match against 
    63     # the route in question. 
    64     def self.compile(route) 
    65       raise ArgumentError unless String === route[0] 
    66       code, count = '', 0 
    67       while route[0] =~ @@section_regexp 
    68         route[0] = route[0].dup 
    69         name = $1 
    70         (name =~ /(\*+)(\w+)/) ? (flag = true; name = $2) : (flag = false) 
    71         count += 1 
    72         if flag 
    73           route[0].sub!(@@section_regexp, "([^,?]+)") 
    74         else   
    75           route[0].sub!(@@section_regexp, "([^\/,?]+)") 
    76         end 
    77         code << "    sections[:#{name}] = $#{count}\n" 
    78       end 
    79       @@compiled_regexen << Regexp.new(route[0]) 
    80       index = @@compiled_regexen.size - 1 
    81       condition = "  when @@compiled_regexen[#{index}] " 
    82       statement = "#{condition}\n#{code}" 
    83       statement << "    return #{route[1].inspect}.update(sections)\n" 
    84       statement 
    85     end 
    86      
     255 
    87256    class Resource 
    88257      # TODO : come up with naming convention and generate helper  
     
    92261      def initialize(resource, procs=[], opts={}) 
    93262        @resource, @procs, @opts = resource, procs, opts 
    94         @procs << proc { ::Merb::RouteMatcher.generate_resources_routes(@resource, @opts)
     263        @procs << proc { [::Merb::Router.matcher, ::Merb::Router.generator].each {|r| r.generate_resources_routes(@resource, @opts) }
    95264      end 
    96265 
     
    102271          yield self.class.new(res, @procs, opts) 
    103272        else 
    104           @procs << proc { ::Merb::RouteMatcher.generate_resources_routes(res, opts)
     273          @procs << proc { [::Merb::Router.matcher, ::Merb::Router.generator].each {|r| r.generate_resources_routes(res, opts) }
    105274        end 
    106275      end 
     
    113282          yield self.class.new(res, @procs, opts) 
    114283        else 
    115           @procs << proc { ::Merb::RouteMatcher.generate_singleton_routes(res, opts) } 
    116         end 
    117       end 
    118     end 
    119        
    120     # add a resource to be compiled for rest style dispatch 
    121     def self.resources(res, opts={}) 
    122       opts[:prefix] ||= "" 
    123       if block_given? 
    124         procs = [] 
    125         yield Resource.new(res, procs, opts) 
    126         procs.reverse.each &:call 
    127       else 
    128         generate_resources_routes(res,opts) 
    129       end 
    130     end 
    131      
    132     # add a resource to be compiled for rest style dispatch 
    133     def self.resource(res, opts={}) 
    134       opts[:prefix] ||= "" 
    135       if block_given? 
    136         procs = [] 
    137         yield Resource.new(res, procs, opts) 
    138         procs.reverse.each &:call 
    139       else 
    140         generate_singleton_routes(res,opts) 
    141       end 
    142     end 
    143      
    144     def self.generate_resources_routes(res,opt) 
    145       with_options :controller => res.to_s, :rest => true do |r| 
    146         r.add "#{opt[:prefix]}/#{res}/:id[;/]edit", :allowed => {:get => 'edit'} 
    147         r.add "#{opt[:prefix]}/#{res}/new[;/]:action", :allowed => {:get => 'new', :post => 'new', :put => 'new', :delete => 'new'} 
    148         r.add "#{opt[:prefix]}/#{res}/new" , :allowed => {:get => 'new'} 
    149         if mem = opt[:member] 
    150           mem.keys.sort_by{|x| "#{x}"}.each {|action| 
    151             allowed = mem[action].injecting({}) {|h, verb| h[verb] = "#{action}"} 
    152             r.add "#{opt[:prefix]}/#{res}/:id[;/]+#{action}", :allowed => allowed 
    153           } 
    154         end 
    155         if coll = opt[:collection] 
    156           coll.keys.sort_by{|x| "#{x}"}.each {|action| 
    157             allowed = coll[action].injecting({}) {|h, verb| h[verb] = "#{action}"} 
    158             r.add "#{opt[:prefix]}/#{res}[;/]#{action}", :allowed => allowed 
    159           } 
    160         end   
    161         r.add "#{opt[:prefix]}/#{res}/:id\\.:format", :allowed => {:get => 'show', :put => 'update', :delete => 'destroy'} 
    162         r.add "#{opt[:prefix]}/#{res}\\.:format", :allowed => {:get => 'index', :post => 'create'} 
    163         r.add "#{opt[:prefix]}/#{res}/:id", :allowed => {:get => 'show', :put => 'update', :delete => 'destroy'} 
    164         r.add "#{opt[:prefix]}/#{res}/?", :allowed => {:get => 'index', :post => 'create'} 
    165       end 
    166     end 
    167      
    168     def self.generate_singleton_routes(res,opt) 
    169       with_options :controller => res.to_s, :rest => true do |r| 
    170         r.add "#{opt[:prefix]}/#{res}[;/]edit", :allowed => {:get => 'edit'} 
    171         r.add "#{opt[:prefix]}/#{res}\\.:format", :allowed => {:get => 'show'} 
    172         r.add "#{opt[:prefix]}/#{res}/new" , :allowed => {:get => 'new'} 
    173         r.add "#{opt[:prefix]}/#{res}/?", :allowed => {:get => 'show', :post => 'create', :put => 'update', :delete => 'destroy'} 
    174       end 
    175     end 
    176      
    177     def self.default_routes 
    178       add "/:controller/:action/:id\\.:format" 
    179       add "/:controller/:action/:id" 
    180       add "/:controller/:action\\.:format" 
    181       add "/:controller/:action" 
    182       add "/:controller\\.:format", :action => 'index' 
    183       add "/:controller", :action => 'index' 
     284          @procs << proc { ::Merb::Router.matcher.generate_singleton_routes(res, opts) } 
     285        end 
     286      end 
    184287    end 
    185288  end 
    186  
    187289end 
  • trunk/lib/merb/merb_server.rb

    r231 r241  
    236236          start(@@merb_opts[:port]) 
    237237        else 
    238           initialize_merb 
    239238          trap('TERM') { exit } 
    240239          mongrel_start(@@merb_opts[:port]) 
  • trunk/lib/merb/mixins/controller_mixin.rb

    r226 r241  
    100100    end 
    101101     
     102    def url(path, o={}) 
     103      ::Merb::Router.generator.generate(path,o) 
     104    end 
     105     
    102106    # parses a query string or the payload of a POST 
    103107    # request into the params hash. So for example: 
  • trunk/lib/tasks/merb.rake

    r203 r241  
    2222    puts "   - #{MERB_ROOT / 'script/merb'}" 
    2323  end 
     24   
     25  desc "freeze the merb framework from svn" 
     26  task :freeze_from_svn do 
     27    puts "Freezing Merb Framework from svn" 
     28    FileUtils.rm_rf MERB_ROOT / 'dist/framework' 
     29    system "svn co http://svn.devjavu.com/merb/trunk/lib #{MERB_ROOT / 'dist/framework'}" 
     30  end 
     31   
    2432end 
  • trunk/specs/merb/merb_dispatch_spec.rb

    r232 r241  
    191191  setup do 
    192192    Merb::Server.allow_reloading=false 
    193     Merb::RouteMatcher.prepare do |r| 
     193    Merb::Router.prepare do |r| 
    194194      r.resource :icon 
    195195      r.resources :posts, :member => {:stats => [:get, :put]},  
     
    206206      r.default_routes 
    207207    end 
    208     Merb::RouteMatcher.compiled_regexen 
    209     Merb::RouteMatcher.compiled_statement 
     208    #puts Merb::Router.compiled_regexen 
     209    #puts Merb::Router.compiled_statement 
     210    #puts Merb::Router.generator.inspect 
    210211  end   
    211212 
     
    221222 
    222223  specify "compile_statement should contain router lambda" do 
    223     Merb::RouteMatcher.compiled_statement.should be_kind_of(String) 
    224     Merb::RouteMatcher.compiled_statement.should =~ /lambda\{\|path/ 
    225     Merb::RouteMatcher.compiled_statement.should =~ /@@compiled_regexen/ 
    226     Merb::RouteMatcher.compiled_statement.should =~ /update\(sections\)/ 
     224    Merb::Router.compiled_statement.should be_kind_of(String) 
     225    Merb::Router.compiled_statement.should =~ /lambda\{\|path/ 
     226    Merb::Router.compiled_statement.should =~ /@compiled_regexen/ 
     227    Merb::Router.compiled_statement.should =~ /update\(sections\)/ 
    227228  end 
    228229   
  • trunk/tools/allison/cache/BODY

    r210 r241  
    402402</div> 
    403403ENDIF:methods 
    404 <div id="spacer"></div><div class="navigation dark index" id="class_wrapper"><div class="list_header"><h3>All classes</h3></div><div class="list_header_link"><a onclick="toggle('class'); toggleText('class_link'); return false;" id="class_link" href="#">Hide...</a></div><div class="clear"></div><div id="class"><form><label for="filter_class">Filter:&nbsp;&nbsp;</label><input type="text" onKeyUp="return filterList('class', this.value, event);" onKeyPress="return disableSubmit(event);" id="filter_class"></input></form></div></div><div class="navigation dark index" id="file_wrapper"><div class="list_header"><h3>All files</h3></div><div class="list_header_link"><a onclick="toggle('file'); toggleText('file_link'); return false;" id="file_link" href="#">Hide...</a></div><div class="clear"></div><div id="file"><form><label for="filter_file">Filter:&nbsp;&nbsp;</label><input type="text" onKeyUp="return filterList('file', this.value, event);" onKeyPress="return disableSubmit(event);" id="filter_file"></input></form></div></div><div class="navigation dark index" id="method_wrapper"><div class="list_header"><h3>All methods</h3></div><div class="list_header_link"><a onclick="toggle('method'); toggleText('method_link'); return false;" id="method_link" href="#">Show...</a></div><div class="clear"></div><div id="method"><form><label for="filter_method">Filter:&nbsp;&nbsp;</label><input type="text" onKeyUp="return filterList('method', this.value, event);" onKeyPress="return disableSubmit(event);" id="filter_method"></input></form></div></div><div class="curve" id="left_curve_0"></div><div class="curve" id="left_curve_1"></div><div class="curve" id="left_curve_2"></div><div class="curve" id="left_curve_3"></div><div class="curve" id="left_curve_4"></div><div class="curve" id="left_curve_5"></div><div class="curve" id="left_curve_6"></div><div class="curve" id="left_curve_7"></div><div class="curve" id="left_curve_8"></div><div class="curve" id="left_curve_9"></div></div><div id="content"> 
     404<div id="spacer"></div><div class="navigation dark index" id="class_wrapper"><div class="list_header"><h3>All classes</h3></div><div class="list_header_link"><a onclick="toggle('class'); toggleText('class_link'); return false;" id="class_link" href="#">Hide...</a></div><div class="clear"></div><div id="class"><form><label for="filter_class">Filter:&nbsp;&nbsp;</label><input type="text" onKeyUp="return filterList('class', this.value, event);" id="filter_class" onKeyPress="return disableSubmit(event);"></input></form></div></div><div class="navigation dark index" id="file_wrapper"><div class="list_header"><h3>All files</h3></div><div class="list_header_link"><a onclick="toggle('file'); toggleText('file_link'); return false;" id="file_link" href="#">Hide...</a></div><div class="clear"></div><div id="file"><form><label for="filter_file">Filter:&nbsp;&nbsp;</label><input type="text" onKeyUp="return filterList('file', this.value, event);" id="filter_file" onKeyPress="return disableSubmit(event);"></input></form></div></div><div class="navigation dark index" id="method_wrapper"><div class="list_header"><h3>All methods</h3></div><div class="list_header_link"><a onclick="toggle('method'); toggleText('method_link'); return false;" id="method_link" href="#">Show...</a></div><div class="clear"></div><div id="method"><form><label for="filter_method">Filter:&nbsp;&nbsp;</label><input type="text" onKeyUp="return filterList('method', this.value, event);" id="filter_method" onKeyPress="return disableSubmit(event);"></input></form></div></div><div class="curve" id="left_curve_0"></div><div class="curve" id="left_curve_1"></div><div class="curve" id="left_curve_2"></div><div class="curve" id="left_curve_3"></div><div class="curve" id="left_curve_4"></div><div class="curve" id="left_curve_5"></div><div class="curve" id="left_curve_6"></div><div class="curve" id="left_curve_7"></div><div class="curve" id="left_curve_8"></div><div class="curve" id="left_curve_9"></div></div><div id="content"> 
    405405IF:title 
    406406<h1 id="item_name">%title%</h1>