new (Raggle::Interfaces::HTTPServerInterface::HTTPServer)

    # File raggle, line 4334
            def initialize(opts)
              @opts = opts

              # grab web UI root
              root = $config['web_ui_root_path'],
              # if it doesn't exist, then eset it to the data directory

              s = WEBrick::HTTPServer::new(
                :BindAddress  => @opts['bind_address'],
                :Port         => @opts['port'],
                :DocumentRoot => $config['web_ui_root_path'],
                :Logger       => WEBrick::Log::new($config['web_ui_log_path'])
              )

              # load templates
              puts "Loading templates from \"#{$config['web_ui_root_path']}/inc\"."
              @templates = Hash::new
              %w{feed feed_list item item_list desc feed_image quit}.each { |tmpl|
                path = $config['web_ui_root_path'] + "/inc/#{tmpl}.html"
                @templates[tmpl] = File::open(path).readlines.join if test(?e, path)
              }

              s.mount_proc('/') { |req, res| res['Location'] = '/index.html' }

              # set up mount points
              s.mount('/', WEBrick::HTTPServlet::FileHandler,
                      $config['web_ui_root_path'], true)

              # set up quit mount point
              s.mount_proc('/raggle/quit') { |req, res|
                quit_thread = Thread::new {
                  $http_server.shutdown
                  sleep opts['shutdown_sleep'];
                  $feed_thread.kill if $feed_thread && $feed_thread.alive?
                  $http_thread.kill if $http_thread && $http_thread.alive?
                }

                res['Content-Type'] = 'text/html'

                # handle quit template
                ret = @templates['quit'].dup
                { 'VERSION'   => $VERSION,
                }.each { |key, val|
                  ret.gsub!(/__#{key}__/, val) if ret =~ /__#{key}__/
                }

                res.body = ret
              }

              # set up feed list mount point
              s.mount_proc('/raggle/feed') { |req, res|
                body = @templates['feed_list'].dup
                ret = ''

                mode = 'default'
                mode = $1 if req.query_string =~ /mode=([^&]+)/

                cat = 'all'
                cat = $1 if req.query_string =~ /category=([^&]+)/

                case mode
                  when 'sort'
                    Engine::sort_feeds
                  when 'invalidate_all'
                    Engine::invalidate_feed(-1)
                    $feed_thread.run
                  when 'add'
                    url = $1 if req.query_string =~ /url=(.*)$/
                    added = Engine::add_feed({ 'url' => url })
                    $feed_thread.run if added and $config['update_after_add']
                  when 'delete'
                    if req.query_string =~ /id=(\d+)/
                      id = $1.to_i
                      Engine::delete_feed(id)
                    end
                  when 'invalidate'
                    if req.query_string =~ /id=(\d+)/
                      id = $1.to_i
                      Engine::invalidate_feed(id)
                      $feed_thread.run
                    end
                  when 'save_feed_list'
                    Engine::save_feed_list
                end

                # build feed list title
                list_title = 'Feeds ' << ((cat && cat !~ /\ball\b/i) ? "(#{cat})" : '')

                # build each feed title
                $config['feeds'].category(cat).each_with_index { |feed, i|
                  str = @templates['feed'].dup
                  title = feed['title'] || $config['default_feed_title']

                  # count unread items
                  unread_count = 0
                  feed['items'].each { |item| unread_count += 1 unless item['read?'] }

                  # convert updated to minutes
                  updated = (Time.now.to_i - feed['updated'] / 60).to_i

                  # handle feed list item template
                  { 'TITLE'         => title || 'Untitled Feed',
                    'URL'           => feed['url'],
                    'ITEM_COUNT'    => feed['items'].size.to_s,
                    'UNREAD_COUNT'  => unread_count.to_s,
                    'INDEX'         => i.to_s,
                    'READ'          => ((unread_count == 0) ? 'read' : 'unread'),
                    'EVEN'          => ((i % 2 == 0) ? 'even' : 'odd'),
                    'UPDATED'       => updated,
                    'CATEGORY'      => cat,
                  }.each { |key, val|
                    str.gsub!(/__#{key}__/, val) if str =~ /__#{key}__/
                  }
                  ret << str
                }

                # handle feed list template
                { 'FEEDS'           => ret,
                  'REFRESH'         => opts['page_refresh'].to_s,
                  'VERSION'         => $VERSION,
                  'CATEGORY'        => cat,
                  'FEED_LIST_TITLE' => list_title,
                  'CATEGORY_SELECT' => build_category_select(cat),
                }.each { |key, val|
                  body.gsub!(/__#{key}__/, val) if body =~ /__#{key}__/
                }

                res['Content-Type'] = 'text/html'
                res.body = body
              }

              # set up feed item list mount point
              s.mount_proc('/raggle/item') { |req, res|
                body = @templates['item_list'].dup
                ret = ''

                feed_id = 0
                feed_id = $1.to_i if req.query_string =~ /feed_id=(\d+)/

                cat = 'all'
                cat = $1 if req.query_string =~ /category=([^&]+)/

                feed = $config['feeds'].category(cat)[feed_id]

                # get feed image
                feed_image = build_feed_image(feed)

                # convert updated to minutes
                updated = ((Time.now.to_i - feed['updated']) / 60).to_i

                # build each feed item title
                feed['items'].each_with_index { |item, i|
                  str = @templates['item'].dup
                  title = item['title']

                  # handle item template
                  { 'TITLE'         => title,
                    'URL'           => item['url'],
                    'DATE'          => item['date'].to_s,
                    'EVEN'          => ((i % 2 == 0) ? 'even' : 'odd'),
                    'READ'          => item['read?'] ? 'read' : 'unread',
                    'FEED_ID'       => feed_id.to_s,
                    'INDEX'         => i.to_s,
                    'CATEGORY'      => cat,
                  }.each { |key, val|
                    str.gsub!(/__#{key}__/, val) if str =~ /__#{key}__/
                  }
                  ret << str
                }

                # handle item list template
                { 'ITEMS'           => ret,
                  'FEED_ID'         => feed_id.to_s,
                  'FEED_TITLE'      => feed['title'] || 'Untitled Feed',
                  'FEED_SITE'       => feed['site'] || '',
                  'FEED_URL'        => feed['url'],
                  'FEED_DESC'       => feed['desc'] || '',
                  'FEED_UPDATED'    => updated.to_s,
                  'FEED_IMAGE'      => feed_image,
                  'REFRESH'         => opts['page_refresh'].to_s,
                  'VERSION'         => $VERSION,
                  'CATEGORY'        => cat,
                }.each { |key, val|
                  body.gsub!(/__#{key}__/, val) if body =~ /__#{key}__/
                }

                res['Content-Type'] = 'text/html'
                res.body = body
              }

              # set up desc window moutn point
              s.mount_proc('/raggle/desc') { |req, res|
                body = @templates['desc'].dup
                ret = ''

                feed_id = 0
                item_id = 0
                cat = 'all'
                feed_id = $1.to_i if req.query_string =~ /feed_id=([-\d]+)/
                item_id = $1.to_i if req.query_string =~ /item_id=([-\d]+)/
                cat = $1 if req.query_string =~ /category=([^&]+)/

                # get feed image
                feed = $config['feeds'].category(cat)[feed_id]
                feed_image = build_feed_image(feed)

                if item_id == -1
                  title = feed['title']
                  body = "description of feed #{title}"
                else
                  item = feed['items'][item_id] || opts['empty_item']
                  title = item['title'] || 'Untitled Item'
                  item['read?'] = true

                  { 'TITLE'         => title,
                    'DATE'          => item['date'].to_s,
                    'READ'          => item['read?'] ? 'read' : 'unread',
                    'URL'           => item['url'],
                    'FEED_IMAGE'    => feed_image,
                    'DESC'          => item['desc'],
                    'REFRESH'       => opts['refresh'],
                    'CATEGORY'      => cat,
                  }.each { |key, val|
                    body.gsub!(/__#{key}__/, val) if body =~ /__#{key}__/
                  }
                end

                res['Content-Type'] = 'text/html'
                res.body = body
              }

              @server = s
            end